はじめに
Unityでは用意しておいたPrefabをInstatinateしてゲーム上に反映するということがしばしばあると思います。
その際のAwakeとStartの挙動について知っておいた方がよさそうな感じだったので、記事に残しておきます。
サンプル
以下のようにComponentAクラスを作成し、これをアタッチしたPrefabAがあると仮定します。
public class ComponentA : MonoBehaviour
{
public void Initialize()
{
Debug.Log("Initializeが呼ばれた");
}
void Awake()
{
Debug.Log("Awakeが呼ばれた");
}
void Start()
{
Debug.Log("Startが呼ばれた");
}
}
PrefabAはExampleクラスから参照され下記のようにInstatinateを行います。
public class Example : MonoBehaviour
{
public GameObject PrefabA;
void Start()
{
var obj = Instantiate(PrefabA, transform);
var prefabA = obj.GetComponent<ComponentA>();
prefabA.Initialize();
}
}
このとき実行順としては以下のようになります。
var obj = Instantiate(PrefabA, transform); // 1. オブジェクト生成 → Awake実行
var prefabA = obj.GetComponent<ComponentA>(); // 2. ComponentAの取得
prefabA.Initialize(); // 3. Initializeの呼び出し
// 4. 次のフレーム開始前にComponentAのStartが実行される
上記のような感じでComponentAのStartはInstatinate直後ではなく次のフレームの先頭で呼ばれる形になります。
なのでStartで参照を設定してInitializeで初期化のような書き方をしているとNull参照でエラーになり、正しく初期化されないので注意が必要です。(まさにそうなりました)
さいごに
Unityでスクリプトを作成したときにデフォルトで記述されるのはStartですが、Startは上記のように実行タイミングが遅い場合があるので、基本的にはAwakeに書くのがよさそうな気がしています。
複数種類のComponentがあってComponentAの後にComponentBの初期化をしたい、とかがあればAwake、Startを使い分けてもいいかもですが、それもExecute Orderで制御できますし、StartとAwakeは元々どういう用途を想定しているのですかね?
短めですが、以上となります。
お読みいただきありがとうございます。
コメント