やりたいこと
シューティングを例として、下記処理を任意順序で実行したい。
1. プレイヤーを移動する。
2. 敵が弾を生成する。
3. 当たり判定を実行する。
デフォルトの処理順序について
Unityでは下記のようなイベント関数 (定義するだけで自動的に呼ばれる関数)の実行順序は定まっていない。
・Awake
・Start
・Update
処理順序の変更(継承なし)
テストとして下記クラス、ObjectA, B, Cを同名のオブジェクトにアタッチしたところ、実行順序はバラバラであった。
(正確には、Unityを再起動したタイミング)
public class ObjectA : MonoBehaviour
{
DateTime dt;
void Awake() {OutLog("Awake"); }
void Start() {OutLog("Start"); }
void Update() {OutLog("Update");}
void OutLog(string funcName)
{
dt = DateTime.Now;
Debug.Log(name + " - " + funcName + " : <frame/time>" + Time.frameCount + "/" + dt.Second + "." + dt.Millisecond);
}
}
スクリプトの実行順序を設定する。
下記サイトのままであるが、
・スクリプトファイルの「インスペクタ -> Execution Order」を選択する。
・下図のようにDefault Timeに数値の少ない順にスクリプトを追加する。
デフォルト時間とは
・公式リファレンスでのデフォルト時間についての定義が見つからなかった。
・試しに、設定する数値を10000刻みで設定したが、特に実行は遅延しなかったため、秒やミリ秒ではなく単なる順序番号として扱われているようだ。
処理順序の変更(継承あり)
実際ゲームを作成していると、ポリモーフィズムを利用したい場合が出てくると思う。
例えば敵クラスを派生した敵1クラス, 敵2クラス…
それらの全ての派生クラスに対して処理順序を設定していたら大変だ。
そこで、基底クラスのみでも処理順序が正しく効くか試してみる。
public class Prefub : MonoBehaviour
{
public GameObject enemyPrefub;
public GameObject playerPrefub;
public void Start()
{
GameObject enemy;
GameObject player;
// Player A,B,C / Enemy A,B,Cを動的に生成する。
enemy = Instantiate(enemyPrefub);
enemy.AddComponent<EnemyC>();
player = Instantiate(playerPrefub);
player.AddComponent<PlayerC>();
enemy = Instantiate(enemyPrefub);
enemy.AddComponent<EnemyB>();
player = Instantiate(playerPrefub);
player.AddComponent<PlayerB>();
enemy = Instantiate(enemyPrefub);
enemy.AddComponent<EnemyA>();
player = Instantiate(playerPrefub);
player.AddComponent<PlayerA>();
}
}

結果
(EnemyC -> PlayerC -> EnemyB -> PlayerB -> EnmeyA -> PlayerA)
意図した結果にならず、生成と同じ順序でUpdate()が呼ばれる。
結論
暫定として、EnemyはEnemyManager, PlayerはPlayerManagerとして一括にまとめて、
PlayerManager -> Update, EnemyManager -> Updateとオブジェクト種別ごとに処理をすればいったんは解決しそうである。
参考サイト
【Unity】狙った順に処理したい時はスクリプトの実行順を指定する
イベント関数
[イベント関数の実行順]
(https://docs.unity3d.com/ja/2018.1/Manual/ExecutionOrder.html)
Script Execution Order Settings
【理解した!】スマホ向けUnity スクリプト実行順の謎