Developer

【初心者Unity】Transform.Findとは?GameObject.Findとの違いは?
2022.01.27
Lv1

【初心者Unity】Transform.Findとは?GameObject.Findとの違いは?

1.はじめに

Transform.Findは、GameObjectを検索(取得)するための関数です。

GameObjectの検索は多くのゲームで必須の操作ですので、使用頻度の高い関数となります。
一方で、良く似た別の関数であるGameObject.Findとの違いがわかり辛く、使い分けがわからないといった面もあるかと思います。

本記事では、Transform.Findの基本的な使い方と、上述のGameObject.Findとの違いについて解説していきます。
具体例を挙げて解説していきますので、しっかりとマスターしましょう!

GameObject.Findについての詳細はこちらの記事をご参照ください。
【初心者Unity】GameObject.Findを具体例付きで解説

2.Transform.Findとは

Transform.Findは、引数に渡した名前を持つGameObjectのTransformを子オブジェクトの中から検索する関数です。
……長ったらしい説明になってしまいましたが、ポイントは以下の3つになります。

① 引数は検索対象のGameObjectの名前(文字列)
② 戻り値はTransformオブジェクト
③ 検索範囲は自身の子オブジェクト

例えば、自身の子オブジェクトの中から「Child」という名前のGameObjectを検索したい場合、以下のように記述します。

Transform child = transform.Find("Child");

ここでひとつ、注意点があります。
transform.Find(…)
と、transformの先頭が小文字になっていることに気を付けてください。
公式リファレンス等でも、Transform.Findと先頭大文字で記載されているため勘違いされるかも知れませんが、transformの部分にはTransformインスタンスを指定する必要があります。
※スクリプト内で単に「transform」と書いた場合、そのスクリプトをアタッチしたGameObject自身のTransformインスタンスを表すことになります。

なお、引数に渡した名称のGameObjectが見つからなかった場合は、NULLが返されます。

3.GameObject.Findとの違い

同じGameObjectを検索する関数として、GameObject.Findというものもあります。
両者の違いは以下になります。

関数の種類 戻り値の型 検索範囲 検索速度 非アクティブ
Transform.Find インスタンス Transform 子オブジェクト 速い 検索可能
GameObject.Find static GameObject ヒエラルキー全体 遅い場合がある 検索不可

関数の種類
上述の通り、Transform.Findはインスタンスな関数です。
一方で、GameObject.Findはstaticな関数ですので、

GameObject child = GameObject.Find("Child");

というように、(クラス名).Findと記述する必要があります。

戻り値の型
こちらも上述の通り、Transform.Findの戻り値はTransformオブジェクトとなります。
そのため、GameObject本体を取得したい場合は、

GameObject child = transform.Find("Child").gameObject;

というように、GameObjectプロパティにアクセスする必要があります。

検索範囲・検索速度
Transform.Findの検索範囲は子オブジェクト内なのに対し、GameObject.Findの検索範囲はヒエラルキー全体となります。
当然、検索範囲の広いGameObject.Findの方が検索に時間が掛かります。

非アクティブ
後述しますが、Transform.Findは非アクティブなGameObjectも検索することができます。
一方で、GameObject.Findは非アクティブなGameObjectの検索に対応していません。

4.GameObject.Findとの使い分け

GameObject.Findとの使い分けについて、ひとつ例を考えてみました。


GunはBulletを子オブジェクトに持つGameObjectで、プレハブから生成されています。
このゲームにおいては、Gunはプレハブを元に自動生成されるとしましょう。

このとき、Gun(4)から自身の子オブジェクトであるBulletにアクセスするためには、どのようなスクリプトを記述したら良いでしょうか?
これは、GameObject.Findでは解決の難しい処理です。

// GameObject.Findを使用した場合

GameObject bullet = GameObject.Find("Bullet");
// ⇒ Gun(1)のBulletにアクセスしてしまうかもしれない

GameObject bullet = GameObject.Find("Gun(4)/Bullet");
// ⇒ 汎用性がない

一方で、Transform.Findでは実現が可能です。
元となるプレハブに、以下のスクリプトをアタッチすれば良いでしょう。

// Transform.Findを使用した場合

GameObject bullet = transform.Find("Bullet").gameObject;
// ⇒ 自分自身の子オブジェクトにアクセス可能!

このように、あるGameObjectの位置を相対的に指定したい場合、Transform.Findは威力を発揮します。

5.具体例

それでは、いくつかの具体例を挙げて、詳細な動作を確認してみましょう。
以下のようなヒエラルキーを作成します。

子オブジェクトの取得
Parentの子オブジェクトの中から、Child1を取得します。
一般的には、Parentにアタッチするスクリプト内で以下のように記述します。

Transform child1 = transform.Find("Child1");

この時、Otherの子オブジェクトであるChild1やヒエラルキーのルートにあるChild1は取得されないことに注意してください。
これは、Findの検索範囲がParentの子オブジェクトに限定されているためです(下図の赤枠)。

同様のことをGameObject.Findで行う場合、階層構造の指定をする必要があります。
GameObject.Findの検索順序は明確でないため、名前だけの指定は避けるべきでしょう。

//GameObject child1 = GameObject.Find("Child1"); // × どのChild1が取得されるかわからない
GameObject child1 = GameObject.Find("Parent/Child1"); // ○ Parentの子オブジェクトであることを明示

孫オブジェクトの取得
ヒエラルキーに以下のGameObjectを追加します。

GrandChild1はChild3の子オブジェクト、つまり、Parentから見れば、子の子で孫オブジェクトとなります。
孫オブジェクトの場合は、単に名前を指定しただけでは取得することができません。
これは、Findの検索範囲がParentの1つ下の階層の子オブジェクトに限定されているためです(下図の赤枠)。

孫以下のGameObjectを取得する場合は、階層を /(スラッシュ)区切りで示す必要があります。

Transform GrandChild1 = transform.Find("Child3/GrandChild1"); // Child3の下のGrandChild1という意味

同様のことをGameObject.Findで行う場合、親オブジェクトから指定する必要があります。

GameObject GrandChild1 = GameObject.Find("Parent/Child3/GrandChild1");

非アクティブな子オブジェクトの取得
ヒエラルキーを以下のように変更します。

子オブジェクトが非アクティブな場合も取得が可能です。
通常の子オブジェクトを取得する場合と同じ記述で、Child1を取得できます。

Transform child1 = transform.Find("Child1");

同様のことをGameObject.Findで行うことはできません
Transform.FindがGameObject.Findと比較して優位な点になります。

親子関係にないGameObjectの取得
/(スラッシュ)区切りの記法を使用することで、親子関係にないGameObjectを取得することができます。
例えば、Otherの子オブジェクトであるChild1を取得する場合は、次のように記述できます。

Transform otherChild1 = transform.Find("/Other/Child1");

先頭の /(スラッシュ)はヒエラルキーのルートを表しています。

もっとも、このようなケースではGameObject.Findを使用するのが一般的でしょう。
あえて、transform.Findを使用するメリットはありません。
ヒエラルキー全体を検索することになるため、検索速度はGameObject.Findと変わりませんし、
先頭に /(スラッシュ)を置いた場合は、非アクティブのものを取得することもできません。

6.おわりに

以上、Transform.Findについて解説しました。
まとめると、
・GameObjectの位置を相対的に指定したい場合
・非アクティブな子オブジェクトを取得したい場合

に使用すると良いのではと思います。
もっとも、GameObjectの取得には、タグを使う方法や、インスペクタを使った方法など様々あります。
その時々の状況に応じて、適切に使い分けられるようになりましょう!

 

連載目次リンク

「初心者のための」Unityゲーム制作 目次
 

Unity実践編 - 目次リンク

実践Unityゲームプログラミング 連載目次