2020/11/09
今回はタイトルにもある通り、UnityのGameObject.Find()
に関するお話です。
事の発端は「第12回 Unity1週間ゲームジャム」で私が作成したゲームのバグです。
うっわ、ほぼ間違いなくここが原因だ。
これで奥の岩の参照が取れちゃって、岩だけ吹き飛びつつも判定は残りっぱなしだから、メッセージだけは出ると…。 pic.twitter.com/3hbotiOHAW— あかざらし (@akaiazarashi) July 9, 2019
この「アザラシが集まると通れる岩」ですが、ヒエラルキーで見ると以下のような感じです。
ツイートのスクリプトが設定されているのが各親オブジェクトのAzarashiRequireRock
なので、ここではtransform.Find()
を使うのが正解ですね。
…で。
このバグはUnityエディタ上で実行している時は発生せず、WebGLで実行している時のみ発生します。
であれば「エディタ上とWebGL上でFindの挙動が違うのでは?」と思ったので、簡単な検証を行ってみました。
各種検証
同じオブジェクト名3つの場合
検証用にシンプルなシーンを用意します。
Cube3つと検証用のスクリプトを設定する空オブジェクトを配置します。加えて確認用にCanvasとUIのTextを作ります。
検証用に以下のスクリプトを作成しました。
オブジェクト名は同じにしないと検証ができないので、タグを付けて区別できるようにします。先のCubeには左から順にFindTest1~3のタグを設定しました。
using UnityEngine; using UnityEngine.UI; public class FindTest : MonoBehaviour { protected Text testText; void Start() { testText = GameObject.FindObjectOfType<Text>(); var cube = GameObject.Find("Cube"); testText.text = cube.tag; } }
これをエディタ上とWebGL上で実行してみます。
「FindTest2」なので真ん中のCubeの参照が取れています。ヒエラルキー上はFindTest1のCubeが一番上なのでちょっと意外。
Cubeは「真ん中→コピーして左→コピーして右」の順で作成したので、その関係かもしれないです。
それ以外はエディタ上とWebGL上で取得できているオブジェクトは同じで、特に違いはないですね。
親子関係を持った同じオブジェクト3つの場合
次にゲームジャムで作ったものと同様、「空の親オブジェクトの子オブジェクトをFind」を試します。
ヒエラルキーの表示はこんな感じ。
先ほどと区別するため、オブジェクトはCylinderをチョイスしました。
スクリプトはCubeのところをCylinderに置き換えるだけなので割愛します。
エディタ上とWebGL上で異なる結果になりました。ゲームジャムの時と同じ感じです。
また、スタンドアローン向けにビルドすると、WebGLと同様の結果になりました。
どちらとも何度試しても同じ結果になるため、ランダムではなく規則性はあるようです。親子オブジェクトの子を取得する場合に順序が異なるのも不思議です。
ただ公式フォーラムでも言われている通り、ドキュメントに順番が明記されていない以上、取得順に依存する処理は書くなということでしょう。実行環境によって違うのであれば尚更です。
https://answers.unity.com/questions/16097/order-of-gameobjectfindgameobjectswithtagstring-ta.html
あとがき
そんなわけで、GameObject.Find()
で取得するオブジェクトについて確認してみました。
(単一オブジェクトを取得する)Find系メソッドを使うのは確実に1オブジェクトが特定できる状況に留めたほうが良いですね。今回ゲームジャムでバグを出してしまったことで、再認識させられる結果となりました。