Unity

Script Execution Orderのちょっと深い話

まずは普通に

Base クラスから派生する Derived1, Derived2, Derived3 と、派生しない Class4, Class5 を以下のようにヒエラルキーに置いてみます。

Test1.png

Start関数内で自分のクラス名を表示する処理を書いて実行すると、以下のように表示されます。

Test1_Result.png

実行順を指定しない場合はコール順が不定になります。
これはUnityのマニュアルにも記載のある通り、規定の動作です。

Orderを指定する

Script Execution Orderで、
Derived1>Derived2>Derived3>Class4>Class5
の順に実行するように設定します。

Test2.png

実行すると、意図通りの表示となりました。

Test2_Result.png

次は、
Class4>Derived1>Derived2>Derived3>Class5
の順に実行するように設定します。

Test3.png

実行すると、意図通りの表示となりました。

Test3_Result.png

ここまでは問題ありません。

基底クラスに設定するとどうなるか

Class4とClass5の間に、Baseクラスを継承したクラス全てをコールするようにしたい場合、Baseクラスに指定すれば良いように思えます。
例えば以下のような設定をしてみます。

Test4.png

すると以下のような表示になりました。

Test4_Result.png

残念ながら、Script Execution Orderに基底クラスを指定しても、そこから派生したクラスには実行順の設定が反映されません。

Script Execution Orderではなく、スクリプトに直に実行順を書いてみます。

Test5.png

実行してみると、不安定な結果となりました。

Test5_Result.png

継承されたクラスの実行順を操作したい場合、必ず派生先のクラスを指定する必要がありそうです。

マルチシーンの場合

Derived1~3とClass4~5を別々のシーンに分けてみます。

Test6a.png

実行順は元に戻しておきます。

Test6b.png

実行してみると、以下のように表示されます。意図通りですね。

Test6_Result.png

しかしここには罠があります。
Test2シーンをアクティブにして、再度実行してみます。

Test7.png

実行すると、以下のように表示されます。

Test7_Result.png

Class4~5とDerived1~3の実行順が入れ替わってしまいました。
Script Execution Orderは同一シーンの中での実行順を操作するもので、シーンを跨いだ実行順の操作はできないようです。
Test1に最優先で実行して欲しいスクリプトがあったとしても、Test2に置かれているスクリプトより前に実行することは出来ない、ということになります。

この時、Awakeはどのタイミングで呼ばれているのでしょうか。
AwakeとStart、それぞれのタイミングでログを出力するようにしてみます。

Test8_Result.png

AwakeとStartはシーンとは関係なく、別々のレイヤーで呼ばれていることが分かります。
例えばTest1に初期化が必要なオブジェクトがあった場合、Awakeで初期化しておけば、Test2ではStartから使えるようになります。

まとめ

  • 基底クラスにScript Execution Orderは効かない
  • スクリプトの実行順はシーンごとに制御され、シーンを跨いでくれない