unityのスクリプトでGameObjectを取得する色々な方法

テクノロジー・プログラミング ゲーム制作

Unityで、スクリプトを組んでいるとGameObjectを取り扱うことが多いと思います。取得する方法はいろいろあるようですが、自分の中でよく使うものをまとめてみました。

概要

記事の中で取り上げる方法は以下の5つです。

  1. Inspectorで設定する
    • 実装的にも処理的にもおそらく一番楽です。
    • 状況によって実装できない場合もあります。
  2. GameObject.Findを使う
    • SceneのGameObjectを検索してきます。他で取得が難しい時は、これが簡単です。
    • ただし、処理は重い(すべてのObjectを検索するので)ので、Startで実行するなど、実行回数を減らす工夫が必要です。
  3. タグでの取得
    • FindGameObjectsWithTagを使って、指定したタグのついたオブジェクトをすべて取得します。
    • 複数のオブジェクトを取得する必要がある時、タグでまとめられるので便利です。
    • タグの管理が多少、面倒ではあります。
  4. オブジェクトの子オブジェクト名を指定して取得する
    • transform.Findで、子オブジェクトの中から指定したオブジェクト名を取得します。
    • Prefabで同じようなオブジェクトが大量にできる時などに便利です。
  5. 子オブジェクトを一括で取得する
    • GetChild(i)をアレンジして取得します。
    • タグの管理が不要になります。transformで探しやすいときに使いやすいです(カードゲームの手札を検索するなど)。

GameObjectを取得する方法

Inspectorで設定する

一つ目は変数だけスクリプト側で用意して、Inspectorから設定する方法です。
やり方としては一番簡単で、検索の処理なども入らないので、やりやすいと思います。ただ、最初からシーンに設定してあるオブジェクトやプレハブしか指定ができません(やり方あるかもですが、自分は知りません)。ゲームの状況に応じて、GameObjectを取得するには他の方法を使う必要があります。

やり方

前提として、HierarchyにObject1とObject2というGameObjectを作成し、Object1にGetGameObjectというスクリプトをアタッチして、Object2のGameObjectを取得する、ということをやってみます。

オブジェクトを用意したHierarchyの状態
  • スクリプトでGameObjectの変数を用意します。
スクリプトを用意
  • ソースコードの中身を用意します。とりあえず、Startでオブジェクトの名前を出力します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GetGameObject : MonoBehaviour
{
    [SerializeField] GameObject Object;

    void Start()
    {
        // オブジェクトに対しての処理を書く
        Debug.Log(Object.name);
    }

    void Update()
    {
        
    }
}
  • スクリプトを保存して、Unityの編集画面に行く。スクリプトをアタッチしているオブジェクトのInspectorを開き、ドラッグ&ドロップで変数にGameObjectを入れる。
Object1のInspector
  • ゲームをスタートすると、処理が実行されています。(Consoleにnameが表示される)

GameObject.Findを使う

オブジェクト名を指定して、Sceneの中にあるGameObjectを取得してきます。

オブジェクト名を指定するだけなので、実装は簡単ですが、オブジェクトを全て検索するので、処理は重くなるようです。これを使う場合、Startで一度呼び出すだけにするなど、呼び出す回数は少なくする工夫をした方がよいそうです。

やり方

先ほどと同じ事例をGameObject.Findでやってみます。

  • スクリプトを用意します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GetGameObject : MonoBehaviour
{
    GameObject Object;

    void Start()
    {
        Object = GameObject.Find("Object2");
    }

    void Update()
    {
        // UpdateでGameObject.Findを使うと重くなるので、Startで取得したほうがよい
        // Object = GameObject.Find("Object2");
        Debug.Log(Object.name);
    }
}
  • ゲームを開始します。処理が実行されています。

タグでの取得

オブジェクトにタグを指定して、FindGameObjectsWithTagでタグ名を指定して取得します。タグのついたオブジェクトを全て取得するので、リスト型になります。

対象が複数に及ぶ時に便利です。タグの管理がやや面倒になるのと、用意できるタグ数は上限があるらしいので注意が必要です。

やり方

オブジェクトを複数取得するので、先ほどの事例にオブジェクトを増やします。Object3とObject4を増やして、Object2とObject4を取得したい場合を考えます。

オブジェクトを追加
  • Inspectorでタグを設定します。今回はTestTagというタグを用意しました。
TestTagというタグを設定
  • スクリプトを用意します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GetGameObject : MonoBehaviour
{
    List<GameObject> ObjectsList;

    void Start()
    {
        ObjectsList = new List<GameObject>();
        ObjectsList.AddRange(GameObject.FindGameObjectsWithTag("TestTag"));

        // foreachで各オブジェクトに処理を行う
        foreach (GameObject obj in ObjectsList)
        {
            // 処理を書く
            Debug.Log(obj.name);
        }
    }
}
  • ゲームを開始します。TestTagのついたGameObjectに処理が行われています。

子オブジェクトの中から検索する

transform.Findを使うと、子オブジェクトから検索ができます。Prefabのように構造が一定で、複数同じ構造のオブジェクトができる時に、便利です。

transformで取得するので、GameObjectとの切り替えには注意が必要です。

やり方

今度は先ほどまでのオブジェクトの子オブジェクトにChildObjectというオブジェクトを用意して、スクリプトを実行しているオブジェクト(Object1)の子オブジェクトを取得します。

子オブジェクトを用意
  • スクリプトを用意します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GetGameObject : MonoBehaviour
{
    GameObject ChildObject;

    void Start()
    {
        ChildObject = this.transform.Find("ChildObject").gameObject;

        // 処理を書く
        Debug.Log(ChildObject.name + "の親は" + ChildObject.transform.parent.name);
    }
}
  • ゲームを開始します。処理が正しく実行されています。

子オブジェクトを一括で取得する

transform.Findでは一つのオブジェクトしか取得できません。GetChild()を使って子オブジェクトを一括で取得、処理を行うことができます。

タグの管理が不要で、transformが固定されているところで処理を行うのに使いやすいです(カードゲームを作っている時にPlayerHandの子にあるカードをすべて取得する、など)。

やり方

今回は、Object1の子オブジェクトを3つに増やして、すべての子オブジェクトを取得します。

オブジェクトを追加
  • スクリプトを用意します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GetGameObject : MonoBehaviour
{
    List<GameObject> ChildsList;

    void Start()
    {
        // 子オブジェクトの数を取得
        int childCount = this.transform.childCount;

        for (int i = 0; i < childCount; i++)
        {
            Transform ChildTransform = this.transform.GetChild(i);
            // 処理を書く
            Debug.Log(ChildTransform.name);
        }
    }
}
  • ゲームを開始します。処理が実行されます。

おわり

探せばもっとありそうですが、自分はここに書いたような方法で取得しています。

深く考えなければ、全部GameObject.Findでいい気もしますが、処理の重さなどを考えると、なるべく検索範囲が少なく済むような方法を選ぶとよさそうです。

コメント

タイトルとURLをコピーしました