Unityがプレイモードに入るときのコールバック呼び出し順 – ケットシーウェア

Unityがプレイモードに入るときのコールバック呼び出し順

プレイボタンをポチっと押してから、実際にプレイ開始されるまでの間に呼ばれるコールバックの呼び出し順を調べてみたのでその覚書。

今回調べたもの

UnityEditor

UnityEngine

スクリプト

スクリプトはこちら

// staticコールバックをテストする場合に定義する
#define TEST_STATIC_CALLBACK
using UnityEngine;
using System.Collections;
#if UNITY_EDITOR && TEST_STATIC_CALLBACK
using UnityEditor;
using UnityEditor.Callbacks;
[InitializeOnLoad]
static class TestInitializeOnLoad
{
private static int _InitializeOnLoadMethodCount = 0;
static TestInitializeOnLoad()
{
Debug.Log("TestInitializeOnLoad : " + _InitializeOnLoadMethodCount);
_InitializeOnLoadMethodCount++;
}
}
static class TestCallbackEditor
{
private static int _InitializeOnLoadMethodCount = 0;
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod()
{
Debug.Log("TestCallbackEditor InitializeOnLoadMethod() : " + _InitializeOnLoadMethodCount);
_InitializeOnLoadMethodCount++;
#if UNITY_2017_2_OR_NEWER
EditorApplication.playModeStateChanged += PlayModeStateChanged;
#else
EditorApplication.playmodeStateChanged += PlayModeStateChanged;
#endif
}
#if UNITY_2017_2_OR_NEWER
static void PlayModeStateChanged(PlayModeStateChange state)
{
Debug.Log("PlayModeStateChanged " + state + " : isPlayingOrWillChangePlaymode = " + EditorApplication.isPlayingOrWillChangePlaymode + " , isPlaying = " + EditorApplication.isPlaying);
}
#else
static void PlayModeStateChanged()
{
Debug.Log("PlayModeStateChanged : isPlayingOrWillChangePlaymode = " + EditorApplication.isPlayingOrWillChangePlaymode + " , isPlaying = " + EditorApplication.isPlaying);
}
#endif
private static int _DidReloadScriptsCount = 0;
[DidReloadScripts]
static void DidReloadScripts()
{
Debug.Log("TestCallbackEditor DidReloadScripts() : " + _DidReloadScriptsCount);
_DidReloadScriptsCount++;
}
#if UNITY_2019_3_OR_NEWER
private static int _InitializeOnEnterPlayModeCount = 0;
[InitializeOnEnterPlayMode]
static void InitializeOnEnterPlayMode()
{
Debug.Log("TestCallbackEditor InitializeOnEnterPlayMode() : " + _InitializeOnEnterPlayModeCount);
_InitializeOnEnterPlayModeCount++;
}
#endif
private static int _RuntimeInitializeOnLoadMethodCount = 0;
[RuntimeInitializeOnLoadMethod]
static void RuntimeInitializeOnLoadMethod()
{
Debug.Log("TestCallbackEditor RuntimeInitializeOnLoadMethod() : " + _RuntimeInitializeOnLoadMethodCount);
_RuntimeInitializeOnLoadMethodCount++;
}
}
#endif
public class TestCallbackBehaviour : MonoBehaviour, ISerializationCallbackReceiver
{
#if TEST_STATIC_CALLBACK
private static int _RuntimeInitializeOnLoadMethodCount = 0;
[RuntimeInitializeOnLoadMethod]
static void RuntimeInitializeOnLoadMethod()
{
Debug.Log("TestCallbackBehaviour RuntimeInitializeOnLoadMethod() : " + _RuntimeInitializeOnLoadMethodCount);
_RuntimeInitializeOnLoadMethodCount++;
}
private static int _AfterSceneLoadCount = 0;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void AfterSceneLoad()
{
Debug.Log("TestCallbackBehaviour AfterSceneLoad() : " + _AfterSceneLoadCount);
_AfterSceneLoadCount++;
}
private static int _BeforeSceneLoadCount = 0;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void BeforeSceneLoad()
{
Debug.Log("TestCallbackBehaviour BeforeSceneLoad() : " + _BeforeSceneLoadCount);
_BeforeSceneLoadCount++;
}
#if UNITY_2019_1_OR_NEWER
private static int _AfterAssembliesLoadedCount = 0;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
static void AfterAssembliesLoaded()
{
Debug.Log("TestCallbackBehaviour AfterAssembliesLoaded() : " + _AfterAssembliesLoadedCount);
_AfterAssembliesLoadedCount++;
}
private static int _BeforeSplashScreenCount = 0;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
static void BeforeSplashScreen()
{
Debug.Log("TestCallbackBehaviour BeforeSplashScreen() : " + _BeforeSplashScreenCount);
_BeforeSplashScreenCount++;
}
#endif
#if UNITY_2019_2_OR_NEWER
private static int _SubsystemRegistrationCount = 0;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void SubsystemRegistration()
{
Debug.Log("TestCallbackBehaviour SubsystemRegistration() : " + _SubsystemRegistrationCount);
_SubsystemRegistrationCount++;
}
#endif
#endif
private int _AfterDeserializeCount = 0;
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
Debug.Log("TestCallbackBehaviour OnAfterDeserialize() : " + _AfterDeserializeCount);
_AfterDeserializeCount++;
}
//private int _BeforeSerializeCount = 0;
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
//Debug.Log("TestCallbackBehaviour OnBeforeSerialize() : " + _BeforeSerializeCount);
//_BeforeSerializeCount++;
}
}

これを適当なGameObjectに張り付けて、プレイボタンをポチっとすればConsoleにログが表示されます。

Unity2020.1.2f1で確認

試しにUnity2020.1.2f1で確認してみたところ以下のようになりました。

※ Enter Play Mode Settingsはオフ(全てリロードされる状態)
※「PlayStart」、「 Play : 時間」と出るログは別物のログ。
※「Error detecting ~」はVS周りのエラーログ(?)

個人的にOnAfterDeserialize()が呼び出されるタイミングが意外ですね。

  • プレイボタン押した直後からInitializeOnEnterModeの間に古いインスタンスのOnAfterDeserializeが呼ばれている点
  • DidReloadScripts直後に呼ばれておりBeforeSceneLoad~AfterSceneLoadの間ではない点

この辺りは気を付けたほうが良さそうです。

Unityのアセット販売中!

ステートマシンの状態遷移やパラメータはエディタで編集でき、
ゲームロジックに依存するステートの挙動はスクリプトで記述可能なエディタ拡張。

詳細はこちら

RPGツクールVXやWOLF RPGエディターのオートタイルに準拠したエディタ拡張。

詳細はこちら

オススメ!