Unityのスクリプトでゲームオブジェクト、コンポーネントを取得する方法

Unityのスクリプトの中で他のゲームオブジェクトの取得、自分自身または他のゲームオブジェクトに設定されているコンポーネント(構成要素)を取得し操作したい事があります。

ゲームオブジェクトに設定するスクリプトもコンポーネントとして扱われるので、他のゲームオブジェクトに設定されたスクリプトに何らかの処理をしてもらいたい時にはコンポーネントの取得をする必要があります。

今まではゲームオブジェクト、コンポーネントの取得に関して掘り下げて説明はしていなかったので、何となく使っていた方もいるかもしれません。

まずはゲームオブジェクトの取得方法を見ていきます。

スポンサーリンク

ゲームオブジェクト取得のテストの準備

ゲームオブジェクトの取得は基本的にStart関数内で取得し、それを変数に入れておきます。
使用する時はその変数を介して実行します。

これは実行時に毎回ゲームオブジェクトの取得をしていると処理に時間がかかる為です。
では実際にゲームオブジェクトを用意して、ゲームオブジェクトを取得するスクリプトを組んでみます。

gettest1

上のようにゲームオブジェクトを階層化しておきます。

1にはObj1タグ
2にはObj2タグ
3にはObj3タグ
4にはObj4タグ

を設定し、それぞれにScript1からScript4までのJavaScriptを作成し設定しておきます。

gettest2

ゲームオブジェクト1は上のようになります。他のゲームオブジェクトにも同じように設定します。

階層の一番上のObj1から子要素を取得するテスト

まずはゲームオブジェクト1から他のゲームオブジェクトを探すスクリプトScript1を作成します。

ゲームオブジェクトを検索したい場合は

GameObject.Find(“ゲームオブジェクトの名前”)

を使います。
アクティブなゲームオブジェクトを検索してくれますが、同じ名前のものを作っていると不具合の原因になるかも?
また、ゲームオブジェクトを全部検索していくので処理に時間がかかります。

今回の例ではゲームオブジェクト2を検索しています。

ゲームオブジェクトに設定したタグで検索したい場合は

GameObject.FindWithTag(“ゲームオブジェクトに設定したタグ名”)

を使います。

ゲームオブジェクト固有のタグが設定されていれば、そのゲームオブジェクトの名前が同じでも指定したタグの物だけ検索出来ます。
FindよりFindWithTagを使った方が処理速度は早いみたいです。

次に現在のゲームオブジェクトの階層の下に取得したいゲームオブジェクトがある場合です。
(さきほど紹介したFindと同じ機能です。あえて使いたいというのでなければFindを使う事をお勧めします)

transform.FindChild(“取得したいゲームオブジェクトまでのパス”).gameObject

transform.FindChildを使うと取得したいゲームオブジェクトまでのパスを指定すればそのゲームオブジェクトのTransform情報が取得出来ます。
TransformはプロパティとしてGameObjectを表すgameObjectプロパティが宣言されていますので、取得したTransform.gameObjectでゲームオブジェクトを取得する事が出来ます。

今回はScript1を設定したゲームオブジェクト1の階層下であるゲームオブジェクト4を取得する為に

transform.FindChild(“2/3/4”).gameObject

という記述をしています。

Transform.FindChildはUnityのスクリプトファイルでは表示されていないようです。
FindChildはおそらくFindと同じなのでスクリプトファイルに載っていないFindChildを使うよりFindを使った方がいいかもしれません。

Unityの実行をして確認したところ、すべて他のゲームオブジェクトの取得が出来ました。

Obj3から他のゲームオブジェクトを取得する方法

次にゲームオブジェクト3から他のゲームオブジェクトを取得するScript3を記述します。

自身のゲームオブジェクトの一番上の階層のゲームオブジェクトを取得したい時は

transform.root.gameObject

とします。
今回の場合はゲームオブジェクト3の一番上の階層であるゲームオブジェクト1を取得しています。

transform.root

でTransformを取得し、プロパティであるgameObjectを得る事でゲームオブジェクトを取得しています。

自身のゲームオブジェクトの親要素を取得する場合

transform.parent.gameObject

とします。
今回の場合はゲームオブジェクト3の親要素であるゲームオブジェクト2を取得しています。

自身のゲームオブジェクトの子要素を取得する場合

transform.GetChild(0)

を使用します。自身の子要素が複数ある場合はGetChildの引数に対応する子要素の数値を指定します。
子要素の子要素を取得する場合は

transform.GetChild(子要素番号).GetChild(子要素番号)

という感じで取得する事も出来ます。
複数の子要素がある場合はfor文等の繰り返し分を使って要素を取得する事が多いと思います。

これでだいたいのゲームオブジェクトの取得の方法がわかりました。
ゲームオブジェクトを探さずインスペクタでゲームオブジェクトを設定しておき、そのゲームオブジェクトを使うという方法もあります。

public var obj1 : GameObject;

上のようにスクリプトにpublic変数でゲームオブジェクト型を宣言しておき、インスペクタでそのゲームオブジェクトを設定すれば、スクリプトで検索する必要はありません。
用途に応じて使い分けるのがいいかもしれません。

Obj2から他のゲームオブジェクトのコンポーネントを取得

ゲームオブジェクトの取得方法がわかったのでそのゲームオブジェクトに設定されているコンポーネントを取得してみます。

Script2を作成します。

自身の親要素を辿ってコンポーネントを検索する時は

GetComponentInParent(コンポーネントの型)

を使用します。
自身に同じコンポーネントがあれば自身のコンポーネントが取得出来るみたいです。

今回は自身の親要素のゲームオブジェクトに設定しているScript1スクリプトコンポーネントを取得しています。

GetComponentInParent(Script1)

自身のゲームオブジェクトに設定されているコンポーネントを取得するには

GetComponent(コンポーネントの型)

とします。

今回は

GetComponent(Script2)

としています。

自身のゲームオブジェクトの子要素であるゲームオブジェクトのコンポーネントを取得するには

GetComponentInChildren(コンポーネントの型)

とします。自身のゲームオブジェクトに同じ型のコンポーネントがある場合は自身のコンポーネントを取得します。

今回は

obj3 = GetComponentInChildren(Transform);
obj4 = GetComponentInChildren(Script4);

と自身のTransformコンポーネントと自身の2段階下の階層のScript4を取得しています。

gettest3

上が実行結果になります。

自身と同じ型のコンポーネントを親要素や子要素から取得したい時は自身のコンポーネントを取得しないよう気をつけなければいけません。不明なバグの原因になるかも!?

JavaScriptは動的型付けなのでコンポーネント取得時は型を指定して取得した方がいいかも!?

最後にJavaScriptで型の動的型付けに対応する為のコンポーネントの取得の仕方をScript4に記述します。
JavaScriptでは型の指定はせず、勝手に型を考慮して変換してくれるスクリプト言語です。

UnityのJavaScriptでも明示的に型指定をしてなくても実行出来ます。
が、変な不具合に遭遇する可能性もあるので、型指定をしてコンポーネントを取得しておきます。

今までは

GetComponent(Script1)

としていましたが、

GetComponent.<Script1>()

として取得します。

わたくしがスクリプトを組んでいる上でコンポーネントの取得方法で不具合が出たという感じはないんですが、最初から指定しておくといいかもしれません。

gettest4

上が実行結果です。

その他のゲームオブジェクト、コンポーネントの取得方法

これまで紹介した方法以外にもゲームオブジェクトの取得、コンポーネントの取得方法はあります。

GameObject.FindGameObjectsWithTag

FindGameObjectsWithTagは引数で指定したタグ名が設定されているゲームオブジェクトをすべて取得する事が出来ます。
同名のタグに設定されているゲームオブジェクトをすべて取得し何らかの処理をしたい時に使用するといいかもしれません。

例えばEnemyタグが設定されている敵すべてに同じ命令を送り、キャラクターを目的地にして攻撃させるとか、
そういった時に使えるかもしれません。

Object.FindObjectOfType

FindObjectOfTypeは引数で指定したタイプのオブジェクト型を探す事が出来ます。
ただし、戻り値としてObject型で返ってくるので使用する時にはキャスト(強制型変換)してから対応する型の変数に代入し使用します。

例えばゲーム内でLightコンポーネントを取得したい時は

typeofを付けず引数にLightだけでも動作しましたが、typeofは付けた方がいいかもしれません。

またキャストを行っていませんがJavaScriptの場合は最後にas Lightを付けて

FindObjectOfType(typeof(Light)) as Light

とした方がいいと思います。
C#の場合は

(Light) FindObjectOfType(typeof(Light))

とするとキャストする事が出来ます。

先ほどのコードではFindObjectOfTypeで取得したオブジェクトをLight型の変数に入れていてコンパイルもそのまま通ってしまって戻り値がObject型かどうかわかりづらいので

↑のような感じで試すとわかりやすいです。

var light : Light = obj as Light;

でキャストしていますが、この行をコメント化し実行しないようにするとDebug.Log(light.type)の部分でエラーになります。
Object型にはtypeというプロパティはありませんというエラーですね。

Lightのtypeプロパティを表示するにはObject型の変数に入っている物をLight型にキャストしないと表示出来ません。
obj変数に入っているのは本当はLight型だけど表向きはObject型という事になっているからそんなプロパティはありませんと言われてるんですね。

ここら辺はオブジェクト指向言語を勉強するとわかると思います。

FindObjectOfTypeは使い辛い!わからん!

という人はあえて使う必要はないと思います・・・(^_^;)

わたくしも現状使っていません。

終わりに

これでUnityのスクリプトでゲームオブジェクト、コンポーネントを取得するやり方が出来ました。
ゲームオブジェクトの名前やタグを使ってゲームオブジェクトを検索したり、自身のゲームオブジェクトから階層を辿って、コンポーネントを取得する方法はいくつもあります。
自分のやりやすいやり方、処理速度を考慮してやり方を変えてみてください。

GetComponentInChildrenやGetComponentInParentでは自分自身のコンポーネントも取得するというのを知らなかったので、
自分自身も勉強になりました・・・・(^_^;)