今回はFind関数について見ていくことにしましょう。
find関数はその名の通り、オブジェクトを探してきてくれる関数です。
うまく使いこなせば、非常に簡単にオブジェクトを取得できる強力な武器となるでしょう。
今回は最初に、二種類のFind関数「GameObject.Find」「Transform.Find」を見ていきましょう。
この二つさえ理解でいれば、大体の物はでも探してくることが可能になります。
それではよろしくお願いいたします。
GameObject.Find関数とは
まずはGameObject.Find関数から見てみましょう!
この関数は一言で言えば「指定した名前のオブジェクトを存在するすべてのアクティブなオブジェクトの中から探し出して取得する」関数です。
プログラム上で、特定のオブジェクトを探して取得したいときに使います。
例えば「Enemy」という名前のオブジェクトがあったとします。
この時GameObject.Find関数を使えば「Enemy」をGameObject型で簡単に取得することができるんです!
とても便利そうですね!
実際に使い方を見ていきましょう。
まずは実際に使用してみよう!
では実際に使ってみましょう。
今回は以下の画面のように、オブジェクトを準備しています。
そして実行されるスクリプトは以下の通りです。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FindTest : MonoBehaviour { // Use this for initialization void Start () { // アクティブなオブジェクトを探す GameObject target1 = GameObject.Find ("FindTarget1"); Debug.Log ("target1 = " + target1); // 非アクティブなオブジェクトを探す GameObject target2 = GameObject.Find ("FindTarget2"); Debug.Log ("target2 = " + target2); } }
単純に「アクティブなFindTarget1」「非アクティブなFindTarget2」を探してログに表示を行っているスクリプトです。
結果はどうなるでしょうか?
アクティブなオブジェクトのみ、ちゃんと探し出せていますね!
また取得したオブジェクトは「GameObject」ですので、座標をいじるなり、コンポーネントを追加するなり、好きに使いましょう!
覚えておくべき重要な3点
名前を引数にするだけで取得できるとは、非常に簡単な関数です!
しかし簡単といえど、いくつか注意する点はあります。
特に覚えておく重要な点は以下の2点でしょう。
①検索対象はアクティブなゲームオブジェクトのみ
②重いので毎フレーム使用しちゃダメ
それぞれ見てきましょう。
①検索対象は【アクティブ】なゲームオブジェクト
これは重要な点です!
この関数ではアクティブなオブジェクトしか探せません。
非アクティブ中のオブジェクトを取得しようとして、うまくいかないという失敗は自分も通りました…
非アクティブなオブジェクトを取得したい場合、後ほど記載する、Transform.Find関数や、組み合わせたテクニックを使用する必要があります。
②重いので毎フレーム使用しちゃダメ
この関数、オブジェクトたちを全検索するため、そこそこ重い処理となっています。
Update関数など、高頻度で行われる関数内で使用するべきではありません。
Start関数などで検索を行い、事前に変数に保持しておくなどといった工夫を行いましょう。
Transform.Find関数とは
次にTransform.Find関数を見てみましょう!
この関数は一言で言ってしまえば「自身のすべての子オブジェクトの中から指定した名前のオブジェクトを探しだして取得する関数」です。
GameObject.Findとの大きな違いは「非アクティブオブジェクトも取得できる」「全検索ではない」この2点と言えるでしょう。
またGameObject.Findと組み合わせることで便利なテクニックも使えますので、しっかりと学んでおきましょう。
まずは実際に使用してみよう!
では実際に使用してみましょうか。
今回はテスト用に以下のようにオブジェクトを用意しています。
そして実行されるスクリプトは以下の通りです。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class FindTest : MonoBehaviour { // Use this for initialization void Start () { // 親オブジェクトを探す GameObject target1 = GameObject.Find ("FindTarget1"); // target1の子オブジェクトの中からアクティブなオブジェクトを探す Transform target2 = target1.transform.Find("FindTarget2"); Debug.Log ("target2(transform) = " + target2); Debug.Log ("target2(gameObject) = " + target2.gameObject); // target1の子オブジェクトの中から非アクティブなオブジェクトを探す Transform target3 = target1.transform.Find("FindTarget3"); Debug.Log ("target3(transform) = " + target3); Debug.Log ("target3(gameObject) = " + target3.gameObject); } }
まず、さっき覚えたFind関数で「FindTarget1」を取得し、その子オブジェクトたちである「FindTarget2」「FindTarget3」を取得しています。
あとはそれを「Transform型」「GameObject型」でログに表示しているだけですね!
実行結果を見てみましょう。
うまくいきましたね!
ちゃんと値が取れています。
また今回は非オブジェクトも取れているのが確認できると思います。
覚えておくべき重要な4点
Transform.Find関数の重要な点は以下のあたりでしょうか。
①static関数ではない
②子オブジェクトの中から検索を行う
③非アクティブなオブジェクトでも検索対象
④戻り値はTransform型
①static関数ではない
static関数ではないため、実際使用する際には「GameObject.Find ("FindTarget1");」のような形ではなく「変数.transform.Find("FindTarget1");」のような使い方になります。
GameObject.Findと呼び出し方が違うため注意しましょう。
②子オブジェクトの中から検索を行う
指定したオブジェクトの、子オブジェクトの中から探すことになります。
全検索ではないのでその点も注意ですね。
③非アクティブなオブジェクトでも検索対象
GameObject.Find関数との大きな違いです。
非アクティブなオブジェクトを探すことができます。
④Transformを返してくれる。
戻り値が、GameObject型ではなくTransform型です。
この点にも注意しましょう。
とはいえ実例で見たように、取得したtransform後ろに「.gameobject」とつけるだけで簡単にGameObjectを取得することができます。
「GameObject.Find」と「Transform.Find」の違いを復習
ここでこの二つの関数の違いを再度確認しましょう。
大きな違い
検索範囲
GameObject.Find・・・全検索
Transform.Find・・・指定したオブジェクトの子オブジェクトから検索
戻り値
GameObject.Find・・・GameObject型で取得できる
Transform.Find・・・Transform型で取得できる
非アクティブオブジェクトに対する挙動
GameObject.Find・・・取得できない
Transform.Find・・・取得できる
違いのまとめ
この辺りが大きな違いですね。
中でも一番の違いは「非アクティブオブジェクトに対する挙動」でしょう。
「GameObject.Findで検索しても、nullが帰ってくる!」なんて時は、非アクティブなオブジェクトを探そうとしていることが原因の大半です。
そのような時は、今回のTransform.Findの実例のような流れで、非アクティブなオブジェクトを取得できるので覚えておきましょう。
①「GameObject.Find関数で親オブジェクトを取得」
②「そのオブジェクトの非アクティブ子オブジェクトをTransform.Find関数で探す」
③「取得したTransform変数.gameobjectでGameObjectを取得」
上記のような流れですね。
より使いこなすためのテクニック!
親の存在しない非アクティブないオブジェクトの取得
※ここから先は少し上級者向けのおまけです。初心者の方はスルーしても問題ありません。
先ほどのGameObject.Find関数とGameObject.Find関数を組み合わせた「非アクティブなオブジェクト取得方法」ですが、一つ弱点があります。
ルートに存在する非アクティブなオブジェクトが探せないんです。
そんな場合の解決方法の一つを記載しておきますので参考にしてみてください。
ルートに存在するの全オブジェクトを取得する「GetRootGameObjects関数」を利用した方法です。
このような状況の時、以下のスクリプトを実行します。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class FindTest : MonoBehaviour { // Use this for initialization void Start () { // ルートに存在する全オブジェクトを取得する GameObject[] gameObjectArray = SceneManager.GetActiveScene().GetRootGameObjects (); // それらをループする foreach (GameObject val in gameObjectArray){ // 名前を表示してみる Debug.Log (val.name); } } }
結果を以下の通りとなります。
ちゃんと非アクティブなオブジェクトも取得できていますね!
あとは、名前でif分を挟んだりすれば、擬似的なFind処理が行えます。
便利関数として用意しておいても良いかもしれませんね。
まとめ
今回はFind関数について学びました。
しかしこの辺りは、まだまだ奥が深いです。
FindGameObjectsWithTag・FindWithTagなどの便利な類似関数がたくさん存在します。
それぞれの特徴を学び、自在にオブジェクトへアクセスしたいものです。