目次
検証環境
Unity:2017.4.5f1
Componentが複数の場合の実行順
基本的にHierarchyやInspectorの配置順に関係なく、Componentの実行順は保証されない。
1つのGameObjectに複数のComponent
Editor上でComponentをAddした順番を記憶してて、最後に追加したComponentから逆順に実行されているように見える。上から順にComponentを貼っつけていった場合、綺麗に降順になる。
- Component3.Awake
- Component2.Awake
- Component1.Awake
- Component3.Start
- Component2.Start
- Component1.Start
- Component3.Update
- Component2.Update
- Component1.Update
次に下のように、Component3、Component2、Component1の順に貼っ付けると結果はこうなる。並び順でもなく追加した順なのがわかる。
- Component1.Awake
- Component2.Awake
- Component3.Awake
- Component1.Start
- Component2.Start
- Component3.Start
- Component1.Update
- Component2.Update
- Component3.Update
だがしかしUnityを再起動したりSceneをUnload/Loadしようものなら、手中に収めていた実行順がたちまちランダムになる。1つのGameObjectについている複数のComponentはおそらく下から順に呼ばれるようになる。この辺の挙動を紐解く。
Componentは何順に実行されるのか
InspectorをDebug表示にするとInstanceIDが表示されるのだが、Componentの呼び出し順はこのIDの昇順になってそうだ。問題なのはこのIDはシリアライズされないので、Unityの再起動やSceneの読み込みなどのタイミングで一定のロジックを通って採番されなおすことになる。
こちらは上から順にComponentを貼っつけた状態。新たにくっつけたComponentは、マイナス方向にある程度幅を取った数字が割り振られていく。IDの昇順なので、このまま実行すればComponent1、Component2、Component3の順に呼び出される。
- Component1.Awake
- Component2.Awake
- Component3.Awake
続いて、1度SceneをUnloadしてLoadし直す。するとプラス方向に下から上へIDが採番され直しているのがわかる。仮にランダムな順番にComponentをくっつけた場合でも下から順に採番され直す。この例だと実行結果は先程と変わらない。
- Component1.Awake
- Component2.Awake
- Component3.Awake
1つのGameObject内であれば採番され直したタイミングで下から順に呼び出されるようになる。たぶん。
これが編集中は新たに貼っつけたComponentとIDの順番があべこべ状態になって実行順がランダムになると錯乱する原因かも。
ツリー状のGameObjectの場合の実行順
以前の記事では他への参照のありなしや、他のGameObjectを使ってみたりして順番に変化が起きるか検証したりもしたが影響がないので分けずに書く。
こちらも上から順にComponentを貼っつけていった場合、そのまま実行すれば綺麗に降順になる。
- GameObject3-1-1.Awake
- GameObject3-1.Awake
- GameObject3.Awake
- GameObject2-1-1.Awake
- GameObject2-1.Awake
- GameObject2.Awake
- GameObject1-1-1.Awake
- GameObject1-1.Awake
- GameObject1.Awake
次に孫、子、親の順で下からつけた場合の結果。親、子、孫の順に呼び出される。
- GameObject1.Awake
- GameObject2.Awake
- GameObject3.Awake
- GameObject1-1.Awake
- GameObject2-1.Awake
- GameObject3-1.Awake
- GameObject1-1-1.Awake
- GameObject2-1-1.Awake
- GameObject3-1-1.Awake
そしてUnityを再起動したりSceneをUnload/Loadしようものなら、手中に収めていた実行順がたちまちランダムになる。 今度は先程のように予測可能な状態ではない。一度ランダムになると変更を一切加えなければUnityを再起動してもシャッフルされないので、何かしらの採番ルールはありそうではあるが、凡人には到底予測不可能な値で採番される。
こちらはComponentを追加した直後のID。実行すれば降順で呼び出される。
name | InstanceID |
---|---|
GameObject1 | -26518 |
GameObject1-1 | -26790 |
GameObject1-1-1 | -26980 |
GameObject2 | -27150 |
GameObject2-1 | -27386 |
GameObject2-1-1 | -27552 |
GameObject3 | -27746 |
GameObject3-1 | -27980 |
GameObject3-1-1 | -28174 |
続いて、1度SceneをUnloadしてLoadし直す。実行結果はランダムと言っても過言ではない。
name | InstanceID |
---|---|
GameObject1 | 13096 |
GameObject1-1 | 13160 |
GameObject1-1-1 | 13274 |
GameObject2 | 13222 |
GameObject2-1 | 13308 |
GameObject2-1-1 | 13124 |
GameObject3 | 13292 |
GameObject3-1 | 13216 |
GameObject3-1-1 | 13200 |
- GameObject1.Awake
- GameObject2-1-1.Awake
- GameObject1-1.Awake
- GameObject3-1-1.Awake
- GameObject3-1.Awake
- GameObject2.Awake
- GameObject1-1-1.Awake
- GameObject3.Awake
- GameObject2-1.Awake
まとめ
InstanceIDはGameObjectの一意な識別子として扱われることがあるIDだが、例に上げたように実行時に変更されることはないが、SceneのLoadやUnityの再起動で変わる可能性がある。また、GameObjectとして書かれてることが多いが、GetInstanceIDメソッドは実際はComponentクラスが持っており、GameObjectに対して呼び出した場合はTransformのIDが返される。
Componentの実行順は予測できないので保証されない(常に変わる可能性がある)として理解しておく必要がある。
それでも制御したい場合は、「Script Execution Order」というものもある。1