Version: 2021.1
言語: 日本語
重要なクラス
重要なクラス - MonoBehaviour

重要なクラス - GameObject

Unity の GameObject クラスは、シーン に存在するあらゆるものを表現するために使用されます。

このページは、Unity の GameObject クラスを使う スクリプト に関するものです。Unity エディターのシーンや Hierarchy でのゲームオブジェクトの使い方については、ユーザーマニュアルの ゲームオブジェクト を参照してください。GameObject クラスのすべてのメンバーを参照するには、GameObject のスクリプトリファレンス を参照してください。

ゲームオブジェクトは、Unity のシーンを構成するブロックであり、ゲームオブジェクトの見た目や機能を決定する機能コンポーネントのコンテナとして機能します。

スクリプティングでは、GameObject クラス はコードに使用できるメソッド群を提供します。それにより、ゲームオブジェクトの検索、接続、ゲームオブジェクト間のメッセージの送信、ゲームオブジェクトに設定されたコンポーネントの追加や削除、シーン内での状況に関連する値の設定など、コードの中でゲームオブジェクトを操作することができます。

シーン状態のプロパティ

スクリプトで変更できるプロパティには、シーン内のゲームオブジェクトの状態に関連するものが多くあります。これらは、エディターでゲームオブジェクトを選択したときに、大抵、Inspector の上部に表示されるコントロールに対応しています。

これらは特定のコンポーネントに関連するものではなく、ゲームオブジェクトの Inspector では、コンポーネントのリストの上に表示されています。

Inspector で表示される典型的なゲームオブジェクトです。ここでは、ディレクショナルライトを使用しています。シーンの状態を示すプロパティが赤で表示されています。
Inspector で表示される典型的なゲームオブジェクトです。ここでは、ディレクショナルライトを使用しています。シーンの状態を示すプロパティが赤で表示されています。

すべてのゲームオブジェクトには、Inspector の上部にシーン内でのゲームオブジェクトの状態を示すコントロールがあり、これらはゲームオブジェクトのスクリプティング API で制御できます。

GameObject クラスで利用できるすべての API の一覧は、GameObject のスクリプトリファレンスを参照してください。

アクティブ状態

アクティブ状態
アクティブ状態

ゲームオブジェクトはデフォルトではアクティブですが非アクティブにすることもでき、非アクティブの場合はゲームオブジェクトに接続されているすべてのコンポーネントがオフになります。これは一般的に不可視状態になり、通常のコールバックや、UpdateFixedUpdate などのイベントを受け取らなくなることを意味します。

ゲームオブジェクトが アクティブ であるかは、ゲームオブジェクトの名前の左にあるチェックボックスで示されます。これは GameObject.SetActive で制御できます。

また、GameObject.activeSelf で現在のアクティブステータスを読み取ることができ、GameObject.activeInHierarchy で、シーンの中で、ゲームオブジェクトが実際にアクティブであるかどうかを確認することができます。ゲームオブジェクトが実際にアクティブであるかどうかは、それ自体のアクティブ状態とそのすべての親のアクティブ状態によって決定されるため、これら 2 つの関数の後者が必要です。

静的状態

ゲームオブジェクトの静的状態
ゲームオブジェクトの静的状態

グローバルイルミネーション、オクルージョン、バッチング、ナビゲーション、リフレクションプローブなど、Unity のシステムの中には、ゲームオブジェクトの静的な状態に依存するものがあります。 GameObjectUtility.SetStaticEditorFlags を使うことによって、Unity のどのシステムがゲームオブジェクトを 静的 とみなすかを制御できます。詳しい情報は、静的ゲームオブジェクト を参照してください。

Tag と Layer

Tag と Layer
Tag と Layer

Tag (タグ) は、シーン内のゲームオブジェクトの種類をマークして識別する方法です。Layer (レイヤー) は似ていますが、レンダリング物理的衝突 などの特定のビルトインアクションから、ゲームオブジェクトのグループを加えたり、除外したりするための別の方法です。

エディターでのタグやレイヤーの使用方法については、TagLayer のユーザーマニュアルを参照してください。

GameObject.tagGameObject.layer プロパティを使って、スクリプトでタグやレイヤーの値を変更することができます。また、CompareTag メソッドを使えば、ゲームオブジェクトのタグを効率的にチェックすることができます。このメソッドでは、タグが存在するかどうかの検証を行いますが、メモリの割り当ては行いません。

コンポーネントの追加と削除

ランタイムにコンポーネントを追加したり削除したりすることができます。これは、ゲームオブジェクトをプロシージャルに作成したり、ゲームオブジェクトの動作を変更したりするのに便利です。ノート: スクリプトコンポーネントやいくつかのタイプのビルトインコンポーネントを、破棄せずにスクリプトを使って enable または disable (有効、または無効) にできます。

ランタイムにコンポーネントを追加する最善の方法は、AddComponent <Type> を使用して、コンポーネントのタイプを < > で囲って指定します。コンポーネントを削除するには、コンポーネント自体に Object.Destroy メソッドを使用する必要があります。

コンポーネントへのアクセス

最も単純なケースは、ゲームオブジェクト上のスクリプトが同じゲームオブジェクトにアタッチされた別のコンポーネントにアクセスする必要がある場合です (ゲームオブジェクトにアタッチされた他のスクリプトもまた、コンポーネントであることに注意してください)。 これを行うための最初のステップは、操作したいコンポーネントインスタンスへの参照を取得することです。これは、GetComponent メソッドを使用して行えます。 通常、コンポーネントオブジェクトを変数に割り当てる必要があります。これは、以下のコードを使用して行います。 この例では、スクリプトは同じゲームオブジェクト上の Rigidbody コンポーネントへの参照を取得します。

void Start ()
{
    Rigidbody rb = GetComponent<Rigidbody>();
}

コンポーネントインスタンスへの参照が取得できた後は、インスペクター上で行うのと同様にプロパティーの値を設定できます。

void Start ()
{
    Rigidbody rb = GetComponent<Rigidbody>();

    // オブジェクトの Rigidbody の質量を変更
    rb.mass = 10f;
}

また、例えばコンポーネントリファレンスのメソッドを呼び出すこともできます。

void Start ()
{
    Rigidbody rb = GetComponent<Rigidbody>();

    // Rigidbody に力を加える
    rb.AddForce(Vector3.up * 10f);
}

ノート: 同じゲームオブジェクトに複数のカスタムスクリプトをアタッチすることができます。あるスクリプトに別のスクリプトからアクセスする必要がある場合は、通常通り GetComponent を使用し、スクリプトクラスの名前 (またはファイル名) を使って、必要なコンポーネントタイプを指定するだけです。

もしゲームオブジェクトに加えられていないコンポーネントタイプを取得しようとすると、GetComponent は null を返します。ランタイムに null オブジェクトの値を変更しようとすると、null 参照エラーとなります。

他のゲームオブジェクトのコンポーネントにアクセスする

スクリプトは単独で動作することもありますが、他のゲームオブジェクトや、より一般的には、他のゲームオブジェクト上のコンポーネントを操作することがよくあります。例えば、料理ゲームでシェフがコンロの位置を知る必要があるとします。Unity には、他のオブジェクトを取得するための様々な方法が用意されており、それぞれが特定の状況に適しています。

Inspector の変数を使ってゲームオブジェクトにリンクする

関連するゲームオブジェクトを見つけるもっとも簡単な方法は public であるゲームオブジェクト変数をスクリプトに加えることです。

public class Chef : MonoBehaviour
{
    public GameObject stove;

    // 他の変数と関数...
}

この変数は、Inspector で、 GameObject フィールド として表示されます。

この変数に、シーンや Hierarchy ウィンドウからオブジェクトをドラッグして割り当てることができます。

プレハブを Project ウィンドウから Inspector ウィンドウの Game Object フィールドにドラッグする
プレハブを Project ウィンドウから Inspector ウィンドウの Game Object フィールドにドラッグする

このオブジェクトは他と同様に GetComponent 関数およびコンポーネントにアクセスできる変数を利用できます。そのため、以下のようなコードを使用できます。

public class Chef : MonoBehaviour {

    public GameObject stove;

    void Start() {
        //コンロの前のシェフ 2 units を開始
        transform.position = stove.transform.position + Vector3.forward * 2f;
    }
}

さらに、もしスクリプトの中でコンポーネント型の public である変数を宣言すると、コンポーネントがアタッチされている任意のゲームオブジェクトをその上にドラッグできます。これはゲームオブジェクト自身ではなくコンポーネントに直接アクセスします。

public Transform playerTransform;

変数でオブジェクトをリンクさせることは、永続的に関連するオブジェクトを処理するときにとても便利です。配列の変数を使って同じ型のオブジェクトを関連付けることができます。しかし、関連付けはランタイムで行うよりも Unity エディター上で行う必要があります。ランタイムにオブジェクトを配置するのが便利な場合がしばしばあります。これを行う方法として Unity では、以下の 2 つの方法があります。

子ゲームオブジェクトの検索

ゲームのシーンでは、アイテム、ウェイポイント、障害物など、同じ種類の多くのゲームオブジェクトを使用することがしばしばあります。これらのオブジェクトは、監視または反応する特定のスクリプトによって追跡されることがあります (例えば、すべてのウェイポイントは、経路探索スクリプトで使用可能です)。変数を使用してこれらのゲームオブジェクトを関連付けることは可能ですが、新しいウェイポイントを 1 つずつスクリプト上の変数にドラッグする必要がある場合、設計面での処理が面倒になります。同様に、ウェイポイントを削除する場合に、欠けているゲームオブジェクトへの変数の参照を削除する必要があります。このような場合、ゲームオブジェクトの群をすべて 1 つの親ゲームオブジェクトの子にすることによって管理するほうが良いことがあります。子のゲームオブジェクトは親の Transform コンポーネントを使用して取得できます (なぜなら、すべてのゲームオブジェクトに暗黙的に Transform があるからです)。

using UnityEngine;

public class WaypointManager : MonoBehaviour {
    public Transform[] waypoints;

    void Start()
    {
        waypoints = new Transform[transform.childCount];
        int i = 0;

        foreach (Transform t in transform)
        {
            waypoints[i++] = t;
        }
    }
}

名前を指定して特定の子オブジェクトを見つけるには Transform.Find メソッドを使用します。 transform.Find("Frying Pan");

これは、ゲーム中に追加や削除が可能な子ゲームオブジェクトを持つゲームオブジェクトの場合に便利です。ゲーム中に手に取ったり置いたりできる道具などは、この良い例です。

メッセージの送信

プロジェクトの編集中に、Inspector でゲームオブジェクト間の参照を設定することができます。ただし、事前に設定できない場合もあります (例えば、ゲーム内のキャラクターに最も近いアイテムを探す場合や、シーンがロードされた後にインスタンス化されたゲームオブジェクトを参照する場合など)。このような場合は、ランタイムにゲームオブジェクト間の参照を見つけたり、メッセージを送信することができます。

BroadcastMessage は、そのメソッドが実装されるべき場所を特定せずに、呼び出しを名前の付いたメソッドに送信できます。BroadcastMessage は、特定のゲームオブジェクトやその子のすべての MonoBehaviour の名前付きのメソッドを呼び出すことができます。任意で、少なくとも 1 つのレシーバーが必要であることを選択できます (エラーが発生する場合もあります)。

SendMessage はもう少し具体的で、ゲームオブジェクトの名前付きメソッドのみへの呼び出しを送信し、その子へは送信しません。

SendMessageUpwards も似ていますが、ゲームオブジェクトとその全ての親の名前付きメソッドに呼び出しを送ります。

名前やタグでゲームオブジェクトを探す

ゲームオブジェクトを認識する情報がある限り、シーンの階層内でゲームオブジェクトを見つけることは常に可能です。個々のオブジェクトを名前で検索するには、GameObject.Find 関数を使用します。

GameObject player;

void Start()
{
    player = GameObject.Find("MainHeroCharacter");
}

オブジェクトまたはその集合をタグを使用して見つけるには GameObject.FindWithTagGameObject.FindGameObjectsWithTag 関数を使用します。

例えば、1 人のシェフキャラクターがいる料理ゲームで、キッチンには複数のコンロがある場合 (それぞれ “Stove” (コンロ) というタグがついています)。

GameObject chef;
GameObject[] stoves;

void Start()
{
    chef = GameObject.FindWithTag("Chef");
    stoves = GameObject.FindGameObjectsWithTag("Stove");
}

ゲームオブジェクトの作成および削除

プロジェクトの実行中に、ゲームオブジェクトを作成したり破棄したりすることができます。Unity では、既存のオブジェクトの新しいコピーを作成する Instantiate メソッドを使ってゲームオブジェクトを作成します。

ゲームオブジェクトをインスタンス化する方法の詳細と例については、ランタイムのプレハブのインスタンス化 を参照してください。

さらに Destroy メソッドは、フレーム更新の完了後か、または選択すると、少し遅延してオブジェクトを破棄します。

void OnCollisionEnter(Collision otherObj) {
    if (otherObj.gameObject.tag == "Garbage can") {
        Destroy(gameObject, 0.5f);
    }
}

Destroy 関数は、ゲームオブジェクト自体に影響を与えることなく、個々のコンポーネントを破棄することができます。よくある間違いは、このスクリプトがアタッチされたゲームオブジェクトを破棄すると仮定することです。

 Destroy(this);

なぜなら、“this” はゲームオブジェクトではなく、スクリプトを表しているからです。実際には、これを呼び出したスクリプトコンポーネントを破棄するだけで、スクリプトコンポーネントが取り除かれたゲームオブジェクトが残ります。

プリミティブ

GameObject クラスは、Unity の GameObject メニューで利用可能なオプションの代わりに、スクリプトベースで プリミティブなオブジェクト を作成することができます。

Unity のビルトインプリミティブのインスタンスを作成するには、GameObject.CreatePrimitive を使用します。これは、指定したタイプのプリミティブをインスタンス化します。利用可能なプリミティブのタイプは、SphereCapsuleCylinderCube、Plane](../ScriptReference/PrimitiveType.Plane.html)、Quad です。

Unity の GameObject メニューで利用できるプリミティブ形状
Unity の GameObject メニューで利用できるプリミティブ形状
重要なクラス
重要なクラス - MonoBehaviour