Unityメンバの初期化をシーケンス図にしてみた

メンバーの初期化

シーケンス図

  • .ctor(コンストラクタ)からメンバの初期化子が呼ばれる。
  • コンストラクタ本体。スクリプティング API を使わない初期化はここで行える。
  • Inspectorで設定している値が反映される。
  • スクリプティング API が使えるのはこれ以降
  • Awake() 自身に閉じている初期化は多分ここで行う。
  • OnEnable() 有効・無効毎に行うことがあればここで行う。
  • Start() 他のオブジェクトを参照する初期化はここで行う。
  • Update()等
  • OnApplicationQuit()
  • OnDisable()
  • OnDestroy()

ConsoleにはInitializeMember()の後にConstructor()が表示されるが、Stack Traceを見ると.ctorからInitializeMember()が呼び出されているので、シーケンス図では逆にした。順番的にはコンストラクタ―本体はInitializeMember()後に実行される。

Inspectorでmemberを100に設定しているのでシーケンス図に追加した。

Play前にすでにコンストラクタは呼ばれ、停止後もDestory後にまたコンストラクタが呼ばれている。

https://www.websequencediagrams.com/examples.htmlにアクターの書き方もあったのでアクターを入れてみた。このツール優秀だなぁ。

シーケンス図テキスト版

title Initialize
actor user
Unity->Test: Constructor() 1
Test->Test: InitializeMember()
note right of Test: Play前に初期化されている
user->Unity: Play
Unity->Test: Constructor() 1
Test->Test: InitializeMember()
Unity->Test: Inspector
Unity->Test: Awake() 100
Unity->Test: OnEnable() 101
Unity->Test: Start() 102
user->Unity: Stop
Unity->Test: OnApplicationQuit() 103
Unity->Test: OnDisable() 104
Unity->Test: OnDestroy() 105
note right of Test: また初期化される
Unity->Test: InitializeMember()
Unity->Test: Constructor() 1

試したTestクラス

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    public int member = InitializeMember();

    static int InitializeMember()
    {
        Debug.Log("Unity->Test: InitializeMember()");
        return 1;
    }

    Test()
    {
        Debug.Log("Unity->Test: Constructor() " + member.ToString());
        member++;
    }

    private void Awake()
    {
        Debug.Log("Unity->Test: Awake() " + member.ToString());
        member++;
    }

    private void OnEnable()
    {
        Debug.Log("Unity->Test: OnEnable() " + member.ToString());
        member++;
    }

    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("Unity->Test: Start() " + member.ToString());
        member++;
    }

    private void OnDisable()
    {
        Debug.Log("Unity->Test: OnDisable() " + member.ToString());
        member++;
    }

    private void OnDestroy()
    {
        Debug.Log("Unity->Test: OnDestroy() " + member.ToString());
        member++;
    }

    private void OnApplicationQuit()
    {
        Debug.Log("Unity->Test: OnApplicationQuit() " + member.ToString());
        member++;
    }
}

GameObjectのアクティブ・非アクティブ、Scriptコンポーネントの有効・無効

InspectorでGameObjectのチェックボックスでアクティブ・非アクティブを切り替え、Test(Script)コンポーネントのチェックボックスで有効・無効を切り替えてみた。

  • Scriptが無効でもGameObjectがアクティブになったときにAwakeが呼ばれる。ちょっと不思議。
  • GameObjectが非アクティブのときにScriptを有効・無効にしてもOnEnable()、OnDisableは呼ばれない。
title Active/非Active, Enable/Disable
actor user
user->GameObject: 非アクティブ
user->Test(Script): 無効
user->Unity: Play
Unity->Test: Constructor() 1
Test->Test: InitializeMember()
Unity->Test: Constructor() 1
Test->Test: InitializeMember()
user->Test(Script): 有効
user->Test(Script): 無効
user->GameObject: アクティブ
Unity->Test: Awake() 100
note right of Test(Script)
初めてアクティブに
なったときに1度だけ
Awake()が呼ばれる
end note
user->Test(Script): 有効
Unity->Test: OnEnable() 101
Unity->Test: Start() 102
note right of Test(Script)
アクティブand有効では
OnEnableが呼ばれる。
1度だけStart()が呼ばれる。
end note
user->Test(Script): 無効
Unity->Test: OnDisable() 103
note right of Test(Script)
無効ではOnDisable()が呼ばれる。
end note
user->GameObject: 非アクティブ
user->Test(Script): 有効
user->GameObject: アクティブ
Unity->Test: OnEnable() 104
user->GameObject: 非アクティブ
Unity->Test: OnDisable() 105
Unity->Test: OnDestroy() 106
Unity->Test: InitializeMember()
Unity->Test: Constructor() 1

横に広がりすぎないように複数行のノートを付けてみた。

初期化を見ようと思ったのでファイナライザーとか定義してなかったな。まぁ、いいかぁ。