Script Execution Orderのちょっと深い話

# まずは普通に

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

![Test1.png](https://qiita-image-store.s3.amazonaws.com/0/66080/c96011d0-84f9-84c7-f063-e7f64be76dc8.png)

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

![Test1_Result.png](https://qiita-image-store.s3.amazonaws.com/0/66080/4f64d79b-4dfe-0825-d368-e2ec4cfd8bb0.png)

実行順を指定しない場合はコール順が不定になります。
これは[Unityのマニュアル](https://docs.unity3d.com/ja/current/Manual/class-MonoManager.html)にも記載のある通り、規定の動作です。

# Orderを指定する

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

![Test2.png](https://qiita-image-store.s3.amazonaws.com/0/66080/d011ff20-2e8b-c725-37ae-3cdcc0e3f7f3.png)

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

![Test2_Result.png](https://qiita-image-store.s3.amazonaws.com/0/66080/274775d7-32d9-0ddf-421d-dd4514226590.png)

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

![Test3.png](https://qiita-image-store.s3.amazonaws.com/0/66080/11ee587f-1129-579a-a8af-1ab05e4b426f.png)

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

![Test3_Result.png](https://qiita-image-store.s3.amazonaws.com/0/66080/235e221b-4661-7d67-2c52-975b7c487c62.png)

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

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

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

![Test4.png](https://qiita-image-store.s3.amazonaws.com/0/66080/06e9b733-2109-9d71-970a-7ecac3bae14f.png)

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

![Test4_Result.png](https://qiita-image-store.s3.amazonaws.com/0/66080/84fc3bbf-44ef-76eb-693d-1191ebe4490d.png)

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

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

![Test5.png](https://qiita-image-store.s3.amazonaws.com/0/66080/b49b7153-1bd9-f87e-7857-6899a263eabc.png)

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

![Test5_Result.png](https://qiita-image-store.s3.amazonaws.com/0/66080/8423e119-5fc7-6230-33ba-2e1ac3719743.png)

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

# マルチシーンの場合

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

![Test6a.png](https://qiita-image-store.s3.amazonaws.com/0/66080/07660511-d0d9-e5b2-43b9-496dd5c2d4a4.png)

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

![Test6b.png](https://qiita-image-store.s3.amazonaws.com/0/66080/108a5479-da47-ff69-d0ca-0c819e922864.png)

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

![Test6_Result.png](https://qiita-image-store.s3.amazonaws.com/0/66080/5c841f2e-4e48-b5fd-e6da-7714c0de81a1.png)

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

![Test7.png](https://qiita-image-store.s3.amazonaws.com/0/66080/5b5120e1-0000-7257-6223-fd929a312129.png)

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

![Test7_Result.png](https://qiita-image-store.s3.amazonaws.com/0/66080/8f61b83c-6424-bb8f-0c23-3cf62cfe3cf7.png)

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

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

![Test8_Result.png](https://qiita-image-store.s3.amazonaws.com/0/66080/c011ef21-a252-dc42-b209-c51efa1a4554.png)

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

# まとめ

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