ゲーム化!tomo_manaのブログ

ゲーム化!tomo-manaのブログ

Unityでゲームを作る方法について紹介しています

Unity学習#19-2 (Unity 2019.4.1f1) 主要イベント Awake, OnEnable, Start, Update, OnDisable のコールタイミング

第19回で、リストの内容をリストの外(セーブデータなど)から渡す処理を実装するにあたって、ゲームオブジェクト間の連携がうまくいかない点がいくつかあったため、Awake()、Enable()/Disable()、Start()/Update() のコールタイミングを調べました。

最初にアクティブになる時のメッセージコール順

f:id:tomo_mana:20201013215634p:plain
メッセージ(初回起動時)

最初にアクティブになる時のメッセージコール順をシーケンス図にすると、上のような感じです。

Awake() と Start() は、それぞれ最初の GameObject.SetActive(true) 後に1回だけ呼ばれます。
Awake() は OnEnable() の直前に、Start() は Update() の直前に呼ばれます。複数のゲームオブジェクトが同時にアクティブになる時は、Awake() と Start() は少し呼ばれ方が異なる点に注意が必要と思われます。

Awake()

Awake() は OnEnable() はゲームオブジェクト単位でセットで呼ばれます。そのため、自身のAwake() が終わって最初のOnEnable() が呼ばれた時、まだ他のゲームオブジェクトはAwake()されていない可能性があるということです。

Start()

一方、Start() は Update() とセットで呼ばれるわけではありません。複数のゲームオブジェクトが同時にアクティブになる時、すべてのゲームオブジェクトが Update() されるより前に、すべてのゲームオブジェクトに Start() が呼ばれます。そのため、最初のUpdate() が呼ばれた時、他のゲームオブジェクトは Start() しています。※ただし、プリファブが混じっていたりする時は、挙動が違うかもしれません。

OnEnable()

OnEnable() は、ゲームオブジェクトがActive()になる度にコールされます。そのため、この処理の中でtransformに変更を加えたりしたくなりますが、最初にアクティブになる時にAwake()とセットで呼ばれることから、他のオブジェクトと協調動作には向いていません。OnEnable() を活用する場合は、Awake() 直後の OnEnable() だけ動作を変えるための状態フラグを定義する必要があります。

各タイミングでできそうな初期化処理

メッセージ 可能な初期化処理
Awake() 参照(gameObject, transformなど)だけを使って内部変数を初期化する
OnEnable() アクティブになる度に初期化すべき内部変数を初期化する
Start() GameObject.Find()など、他のゲームオブジェクトがアクティブでないと使えない方法を使って内部変数を初期化する
Update() アクティブになった時に必要なその他の処理を行う(状態フラグで処理を切り替える)

どのゲームオブジェクトからコールされるのか?

尚、Awake()、OnEnable()、Start()、Update() 時にどのゲームオブジェクトから順に呼ばれるかは、ゲームオブジェクトが作られた順、またはゲームオブジェクトが保存されるときに付加されるID(GUID)で決まります。GUID は乱数を使って生成されるため、そのままではゲームオブジェクトが呼ばれる順番を制御できません。ゲームオブジェクトを呼ぶ順番を決めるには、Project Settings の Script Execution Order を使います。

Script Execution Order

(1) Unityメニューから、Project > Project Settings..
(2) Project Settingsメニューから、Script Execution Order を選択
(3) 画面下の [+▼] を選択して、実行順を規定したいC#スクリプト(ゲームオブジェクトではない)を選択します
(4) リストにC#スクリプト名が追加されるので、右側にある数字に値を入れます。
 値が小さい順(昇順)に並び変わります。値が小さい方から順に呼び出されます。

非アクティブ時の動作

OnDisable()

f:id:tomo_mana:20201013221320p:plain
メッセージ(OnDisable)

スクリプトが所属する GameObject が SetActive(false) されるとき、OnDisable() が呼ばれます。OnDisable() は、上記と異なり、親子関係に沿って呼ばれます。親、子、孫ゲームオブジェクトがあって、親ゲームオブジェクトがSetActive(false)されると、孫→子→親の順にゲームオブジェクトが非アクティブになります。

(参考)
イベント関数の実行順序 - Unity マニュアル