【Unity】スクリプトの実行順序を制御する

こじゃらこじゃら

スクリプトの実行順序を自分で指定する方法を教えてほしいの~

このはこのは

Script Execution Orderの設定から可能だわ。

通常、同じUnityイベントから実行されるスクリプトの実行順序は不定です。

参考:Script Execution Order- Unity マニュアル

例えば、あるMonoBehaviourスクリプトAとBで定義されるUpdateメソッドの実行順序は前後する可能性があります。

このような実行順序の入れ替わりが困る場合、Script Execution Orderを設定して決まった順序でスクリプトが実行されるように制御することができます。

例えば、スクリプトの初期化を決まった順番で実行させたい場合に重宝します。

ただし、実行順序に依存したプログラムの場合、設定ミスで思わぬバグを生むことになる可能性があり、取り扱いには十分注意する必要があります。

本記事では、Script Execution Orderを設定してスクリプトの実行順序を制御する方法を解説していきます。

動作環境
  • Unity2021.1.20f1

スポンサーリンク

Script Execution Orderの設定方法

メニューのEdit > Project SettingsよりProject Settings画面を開き、左のリストよりScript Execution Orderを選択します。

すると、以下のような設定画面が開きます。

画面には、スクリプトとその実行順序の数値が一覧で表示されています。ここに実行順序を制御したいスクリプトを追加していく形になります。

実行順序は値が必ず値が小さいものが先に実行されるようになります。一覧は値が小さい順にソートされており、上から順番に実行されるようなります。

Default Timeと書かれた項目は、実行順序が設定されていないスクリプト(実行順序の値が0)を表しています。

実行順序の定義を追加する

スクリプトをリストにドラッグ&ドロップするか、右下の+ボタンからスクリプト名を選択することで一覧に追加できます。

実行順序の値を直接編集したり、項目をドラッグすることで実行順序を変更することができます。

設定が終わったらApplyボタンをクリックして適用します。設定を戻したい場合はRevertボタンをクリックします。

動画の例では、ScriptB→ScriptC→ScriptAの順に実行する設定にしました。

サンプルスクリプト

先の例で追加したサンプルスクリプトの内容です。

ScriptA.cs
using UnityEngine;

public class ScriptA : MonoBehaviour
{
    private void Awake()
    {
        print("ScriptA.Awake() called!");
    }

    private void Start()
    {
        print("ScriptA.Start() called!");
    }

    private void Update()
    {
        print("ScriptA.Update() called!");
    }
}
ScriptB.cs
using UnityEngine;

public class ScriptB : MonoBehaviour
{
    private void Awake()
    {
        print("ScriptB.Awake() called!");
    }

    private void Start()
    {
        print("ScriptB.Start() called!");
    }

    private void Update()
    {
        print("ScriptB.Update() called!");
    }
}
ScriptC.cs
using UnityEngine;

public class ScriptC : MonoBehaviour
{
    private void Awake()
    {
        print("ScriptC.Awake() called!");
    }

    private void Start()
    {
        print("ScriptC.Start() called!");
    }

    private void Update()
    {
        print("ScriptC.Update() called!");
    }
}

Awake、Start、Updateイベントのタイミングでログを出力しています。

実行結果

設定通り、ScriptB→ScriptC→ScriptAの順に呼び出されることが確認できました。

Script Execution Orderの設定ファイル

実行順序の情報は、スクリプトに紐づくmetaファイル内部に保存されています。

ScriptA.cs.meta
fileFormatVersion: 2
guid: ca48b0f4ad66cea4989108d6a33f06f8
MonoImporter:

  ・・・(中略)・・・

  executionOrder: 50

metaファイルのexecutionOrderの値をテキストファイルで直接編集しても実行順序を設定できます。

UnityプロジェクトをGit管理している場合、スクリプトの実行順序を変更すると該当のmetaファイルが更新差分として現れるため、これをコミットすればOKです。

こじゃらこじゃら

一か所の設定ファイルではなくて、個別のmetaファイルに保存されているんだね。

デフォルトの実行順序を指定するDefaultExecutionOrderについて

公式リファレンスからは削除されていますが、DefaultExecutionOrder属性をMonoBehaviour継承クラスに指定してデフォルトの実行順序を設定する方法が存在します。

[DefaultExecutionOrder(100)]
public class MyClass: MonoBehaviour
{
}

Script Execution Orderがmetaファイルに設定されている場合、この設定値に上書きされます。

未設定の場合は一覧に表示されませんが、内部的にはDefaultExecutionOrder属性に指定した引数の優先順位でスクリプトが実行されるようです。

参考:https://forum.unity.com/threads/undocumented-but-public-defaultexecutionorder-attribute.530618/

注意

実行順序が変わっても設定項目に表示が反映されないため、不用意にDefaultExecutionOrderで実行順序を設定すると、誤解を招いてしまう可能性が高くなります。

混乱を避けたい場合、基本的にmetaファイル側(GUIから)で実行順序を設定するのが安全です。

Script Execution Orderで実行順序を制御できないもの

スクリプトの実行順序を設定していても、例えば次の呼び出し順序の制御までは行えないので注意する必要があります。

実行順序を制御できないもの
  • コルーチン
  • RuntimeInitializeOnLoadMethodAttribute属性のメソッド

さいごに

Script Execution Orderの設定を変更してスクリプトの実行順序を変更する方法を解説しました。

実行順序を任意に指定することは便利な反面、処理順序に依存しすぎると設定ミスで思わぬバグを生むきっかけになり注意が必要です。

目的を決めて効果的に使っていくと良いでしょう。

参考サイト

スポンサーリンク