徒然エンジニアブログ

徒然エンジニアブログ

理系東大生がプログラミングを中心に様々なことについて情報発信していきます!

【Unity】Find関数の使い分け(オブジェクトを見つける時)

Unityでのオブジェクトの見つけ方

unityをやっているとゲームオブジェクトをスクリプトから操作するために、変数に格納したいというときがあると思います。
今回はその方法を説明していきたいと思います!

インスペクタから直接選択する

publicか[SerializedField]といったアクセス修飾子をつけてインスペクタ上で指定できるようにする。
アクセス修飾子については以前書いているのでそちらを参考にしてください。
turedureengineer.hatenablog.com

これが一番簡単かつ負荷が少ない処理なのでできるならばこれがいいです。

GameObject.Find("取得したいオブジェクトの名前")

まず一つ目がこちらです。これが最もポピュラーといっていいのではないでしょうか?
使い方は簡単ですが、注意点が二つあります。

一つ目は処理が重いことです。全てのオブジェクトの名前の中から条件に合うものを選ぶためです。
Update関数の中で毎回呼ぶのは絶対に避けましょう。
Start関数で一度だけ探して、そのあとは変数として保持するようにしましょう。

二つめがActiveなものしか取得できないことです。非アクティブなものを取得したい時は後述するtransform.Find()を使いましょう。

三つ目がプレファブで作られたゲームオブジェクトを取得したい時はしっかり(Clone)まで入れないといけないことです。

実際の使い方を見てみます。

//object1という名前のゲームオブジェクトを取得したい時
GameObject object1 = GameObject.Find("Object1");

GameObject.FindGameObjectWithTag("タグの名前")

これはオブジェクトの名前ではなく、オブジェクトにつけられたタグの名前からオブジェクトを見つけるものです。

注意点としてGameObject.Find()と同じくアクティブなものしか取得できないことです。

実際の使い方を見てみます。

//objectというタグ名のゲームオブジェクトを取得したい時
GameObject object1 = GameObject.FindGameObjectWithTag("object");

GameObject.FindGameObjectsWithTag("タグの名前")

GameObject.FindGameObjectsWithTag()はタグの名前がついたゲームオブジェクトを複数取得して配列に格納する関数です。
一つ前のものと見比べて複数形の"s"がついていることがわかると思います。

これもアクティブなものしか取得することはできません。

せっかく配列に格納したなら一度に操作したいことが多いと思います。
そこでタグの名前からオブジェクトを取得してまとめて操作するプログラムの例を見てみましょう。

//objectというタグ名のゲームオブジェクトを複数取得したい時
GameObject[] objects = GameObject.FindGameObjectsWithTag("object");
//配列の要素一つ一つに対して処理を行う
foreach(object in objects)
{
    //今回は例として取得したオブジェクトを非アクティブにしてみる
    object.SetActive(false);
}

(親オブジェクト).transform.Find("オブジェクトの名前").gameObejct

これの最大の利点は非アクティブなオブジェクトでも取得できる点です。
しかしながらこれはtransform型になってしまうので最後に.gameObjectをつけて変換する必要があります。

またこオブジェクトしか取得できないことにも注意してください。
親オブジェクトはこれまでに上げて方法などで別途取得する必要があります。

孫オブジェクトはヒエラルキーの順に/で」繋げることで取得することができます。

ヒエラルキーが下のようになっている時の実際のスクリプトを見てみましょう。
f:id:turedureengineer:20181117201102p:plain

GameObject parent = grandParent.transform.Find("Parent").gameObject;

GameObject child1  = parent.transform.Find("Child1").gameObejct;
GameObject child2  = grandparent.transform.Find("Parent/Child2").gameObejct;

最後に

一番いいのは最初にあげたインスペクタ上で指定することです。
これができない場合、例えばプレファブで自動生成されたものをもつける場合にFind関数を使いましょう。
アクティブならGameObject.Find、非アクティブならtransform.Findというように使い分けるといいでしょう。

unityでのオブジェクトの見つけ方は様々あってわかりにくいと思うのでぜひこれを参考にしてみてください。