この記事はUnityの基本的な使い方を解説するシリーズの一つで、今回はC#スクリプトからゲームオブジェクトを検索してその参照を取得する方法について詳しくご説明します。
Unityでゲームを作っていると、ゲーム実行時にシーン上のゲームオブジェクトを探したくなる場面が出てくると思うので今回の内容はそのようなときに役立ちます。
ゲームオブジェクトを検索できる「Find系関数」の使い方
では早速ですがゲームオブジェクトを検索できる関数(いずれも「Find」という名前がついているので、ここでは便宜的に「Find系関数」と呼ぶことにします)の使い方をご紹介していきます。
一つのゲームオブジェクトを検索して取得する方法
まず、シーン内から1つのゲームオブジェクトを検索して取得したい場合は主に次の2通りの方法があります。
- GameObject.Find関数で「ゲームオブジェクトの名前」から検索
- GameObject.FindWithTag関数で「ゲームオブジェクトのタグ」から検索
Find関数
シーン内でゲームオブジェクトの名前を検索し、一致する名前を持つ最初のゲームオブジェクト1つを取得します。
GameObject go = GameObject.Find("TestGameObject");
FindWithTag関数
シーン内でゲームオブジェクトをタグ名から検索し、一致するタグを持つ最初のゲームオブジェクト1つを取得します。
GameObject go = GameObject.FindWithTag("TestTag");
FindWithTag関数はFind関数よりも高速に動作するので、できればこちらを使うようにしましょう。
複数のゲームオブジェクトを検索してまとめて取得する方法
次にシーン内の複数のゲームオブジェクトを検索してまとめて取得する方法としては「FindGameObjectsWithTag関数」を使う方法があります。
GameObject[] go = GameObject.FindGameObjectsWithTag("TestTag");
使い方はFindWithTag関数と同じで、こちらは戻り値が配列になっているだけです。
あるゲームオブジェクトの子の中から検索する方法
あるゲームオブジェクトの子の中から名前で検索して取得したい場合はTransform.Find関数を使います。使い方はGameObject.Findと同様で
Transform child = transform.Find("ChildName");
のように書くだけです(※transformのところには親となるゲームオブジェクトのトランスフォームを指定してください。上の例ではC#スクリプトがアタッチされているゲームオブジェクトの子の中から検索します)。ただしこちらは戻り値がTransform型になっている点には注意しましょう。
なお検索に使う名前には階層を指定することもできます。例えば「Test/Name」と書けば、子のTestというゲームオブジェクトの中のNameという名前のゲームオブジェクト(つまり孫オブジェクト)のトランスフォームを取得できます。
ゲームオブジェクトを検索するときの注意点
では最後にC#スクリプトからゲームオブジェクトを検索するときの注意点を一つ書いておきます。その注意点とは、ゲームオブジェクトの検索処理は重いということです。
したがって、例えば上記のようなゲームオブジェクトの検索を行う関数をUpdate関数内から毎フレーム呼び出す、といったことは避けたほうがよいでしょう。
ただそうなると「じゃあどうすればいいの?」と思う方もいらっしゃるかもしれませんので、ここでは代替案を2つご紹介しておきますね。
- そもそもゲーム実行中にゲームオブジェクトを検索しないようにする
- どうしても検索が必要な場合は検索結果を変数にキャッシュしておく
そもそもゲーム実行中にゲームオブジェクトを検索しないようにする
まず一つ目の案は、そもそもゲーム実行中にゲームオブジェクトを検索しなくてもいいようにしておくことです。
例えば最初からシーンにあるゲームオブジェクトなら、わざわざゲーム実行中に検索しなくてもインスペクターからそのゲームオブジェクトを登録できるようにしておけばいいだけの話です。このように少し工夫するだけでゲーム実行中に検索処理を使う必要性を減らすことができます。
どうしても検索が必要な場合は検索結果を変数にキャッシュしておく
次に二つ目の案は、どうしても検索が必要な場合は検索結果を変数にキャッシュしておくことです。
1つ目の案では「そもそも検索の必要がないものは検索しない」というご提案をしましたが、そうは言っても「ゲーム実行中に生成したプレハブのインスタンス」等はゲーム実行中に検索しないと取得できません。
このような場合はFind系関数を使わざるを得ませんが、使う場合は毎フレーム検索するのではなく、できるかぎり検索結果を使い回した方が賢いと言えます。そこでゲームオブジェクトの検索結果は変数にキャッシュ(=一時保存)しておきましょう。
using UnityEngine; public class SampleScript : MonoBehaviour { GameObject result; void Start() { result = GameObject.FindWithTag("TestTag"); } void Update() { result.transform.position += Vector3.up * Time.deltaTime; } }
このようにすることで無駄な処理を省くことができます。
おわりに
以上、Unityでシーン内のゲームオブジェクトをC#スクリプトから検索する方法についてご説明しました。
ゲームオブジェクトの検索処理はなるべく使わないほうがスマートですが、使いこなせると便利ではあるのでぜひ上記の内容を参考にしていただければと思います。