ドキュメント

Unity Engine

Unity Engine

ドメイン リロードが無効な状態で再生モードに入る

Enter 再生モードでドメインリロードを無効にするとアプリケーションステートにどのような影響があり、コードでこれらの影響を補うことができるかを理解します。
読み終わるまでの所要時間 16 分最終更新 3日前

スクリプティング ドメインは、アプリケーション ドメインや単にドメインとも呼ばれ、Unity のマネージ スクリプティング環境の中核となる特徴です。ドメインは、特定のアプリケーション専用のメモリーの分離されたセクションです。このセクションには、アプリケーションに必要なコンパイル済み型が含まれ、アセンブリと呼ばれる論理ユニットにグループ化されます。また、マネージメモリのさまざまなセクションの変数やオブジェクト参照の値など、現在のアプリケーションステートを表すデータも含まれます。
デフォルトでは、Unity は再生モードに入るとドメインをリロードしてアプリケーション ステートをリセットします。再生モードに入る前にステートをリセットすることは、多くの場合、新しいビルドの開始時と同じようにアプリケーションを起動するために役立ちます。例えば、前の再生モード セッションで増分された静的カウンタは、次のセッションで再びゼロから開始する必要があります。ただし、ドメインリロードは時間のかかる操作でもあり、編集モードと再生モードを頻繁に切り替えるとイテレーション時間に悪影響を与えます。イテレーション時間を短縮するために、再生モードに入るときにドメインリロードを使用不可にできますが、その場合は、コードでステートを手動でリセットする必要があります。
注
Unity は、スクリプトの変更を検出すると、アセットデータベースの更新の一環としてドメインリロードも実行します。これは、再生モードに入る際のドメイン リロードがディセーブルの場合でも発生します。アセットデータベースの更新のタイミングと方法の詳細は、アセットデータベースの更新 を参照してください。

再生モードに入るときのドメイン リロードのディセーブル化の影響

ドメインのリロードを使用不可にすると、以下のようになります。
  • 非シリアライズ フィールドは、編集モードに戻ったときに再生モード中に割り当てられた値を維持します。これは、MonoBehaviour (プレハブのフィールドを含む)、ScriptableObject、独自のカスタム C# 型など、すべてのスクリプトタイプのフィールドに適用されます。異なるコンテキストでシリアライズされるものとされないものの詳細については、シリアル化規則 を参照してください。
  • 静的変数は、再生モード セッション間でその値を維持します。
  • 静的イベントは、再生モード セッション間で登録された加入者を維持します。
  • [ExecuteInEditMode]
    または
    [ExecuteAlways]
    でマークされたスクリプトに対する追加の
    OnDisable
    または
    OnEnable
    の呼び出しはありません。
再生モードセッション間のデータの持続性を補正し、新しいアプリケーションステートで再生モードを開始するには、コードステートをリセットする必要があります。
ドメインとシーンのリロードの無効化の影響についての詳細は、『 ドメインとシーンのリロードの無効化 』を参照してください。

コードからステートをリセットする

ドメインの再ロードがディセーブルの場合、静的フィールドの値と静的イベントに割り当てられたハンドラは再生モードの実行間で維持されます。以下のコード例では、任意のキーボードキーを押すごとに増加する静的カウンタがあります。コードは静的イベント
EditorApplication.playModeStateChanged
を処理するメソッドも登録します。
ドメイン リロードを有効にすると、Unity は再生モードの開始時にこのコードを再初期化し、カウンタ値やイベント ハンドラーの登録など、前回の再生モード実行のステートを消去します。ドメイン リロードをディセーブルにすると、カウンタ値とイベント ハンドラー登録の両方が前回の実行から保持されます。再生モードの次の実行では、カウンターは前回の実行終了時の値で始まり、イベントメソッドのイベント発生で複数回呼び出され、コンソールに複数の "Exiting 再生モード!" メッセージが生成されます。
// Copy-paste this code into a MonoBehaviour script attached to a GameObject in your project.// Run it with domain reload enabled and then with domain reload disabled and note the different behavior.using UnityEngine;#if UNITY_EDITORusing UnityEditor;#endifpublic class StateResetExample :MonoBehaviour{ // With domain reload disabled this counter won't reset to zero on exiting Play mode 静的 int counter = 0; void Start() { // Register handler#if UNITY_EDITOR EditorApplication.playModeStateChanged += OnExitPlayMode;#endif } void Update() { if (Input.anyKeyDown) { counter++; Debug.Log("Counter: " + counter); } }#if UNITY_EDITOR private static void OnExitPlayMode(PlayModeStateChange state) { if(state == PlayModeStateChange.ExitingPlayMode) { // With domain reload disabled this message prints multiple times after the first Play mode run Debug.Log("Exiting Play mode!"); } }#endif}
再生モード実行の間にカウンタを明示的にリセットし、イベントハンドラーを登録解除するコードで問題の動作を修正できます。これは、再生モードの開始時または再生モードの終了時に行うことができます。

再生モード終了時のステートのリセット

多くの場合、ステートをリセットするのは、再生モードに入るときではなく、終了するときに行うのが最も効率的です。
EditorApplication.playModeStateChanged
イベントとその
ExitingPlayMode
enum 値を使用して、再生モードの終了イベントを取得し、その時点でステートをリセットできます。以下の例では、再生モード終了のイベントハンドラーを使用してそれ自体を登録解除しますが、この時点で、このメソッドを使用してほかの静的イベントハンドラーも登録解除できます。
using UnityEngine;#if UNITY_EDITORusing UnityEditor;#endifpublic class StateResetOnExit :MonoBehaviour{ 静的 int counter = 0; void Start() {#if UNITY_EDITOR EditorApplication.playModeStateChanged += OnExitPlayMode;#endif } // Update is called once per frame void Update() { if (Input.anyKeyDown) { counter++; Debug.Log("Counter: " + counter); } }#if UNITY_EDITOR private static void OnExitPlayMode(PlayModeStateChange state) { if(state == PlayModeStateChange.ExitingPlayMode) { Debug.Log("Exiting Play mode!"); Debug.Log("Unregistering handler."); // Unregister the handler so it doesn't affect the next Play mode run EditorApplication.playModeStateChanged -= OnExitPlayMode; Debug.Log("Resetting counter."); // Reset the counter so it starts from 0 on the next Play mode run counter = 0; } }#endif}
EditorApplication.playModeStateChanged
は
UnityEditor
名前空間にあるため、Unity エディター内の再生モードでのみ機能し、スタンドアロンプレイヤービルドでは機能しません。
再生モードに加えて編集モードでコードを実行する場合は、再生モード終了時のステートのリセットに頼ることはできません。コードは編集モード中に静的変数を変更する可能性があるため、代わりに再生モードになったときに変数をリセットする必要があります。
注
編集モードで実行するスクリプトでは、ドメインリロードを無効にすると
MonoBehaviour.OnDisable
がスキップされ、シーンリロードを無効にすると
MonoBehaviour.OnDestroy
がスキップされます。そのため、これらのメソッドは、このようなスクリプトのステートをリセットするのには不適切です。詳細は、ドメインとシーンのリロードの無効化の詳細 を参照してください。

再生モードに入るときのステートのリセット

再生モードに入るときにステートをリセットすることもできます。これは、既存の再生モードイベントのキャプチャでプラットフォーム固有の問題が発生した場合や、編集モードでも実行されるコードがある場合に、便利な代替手段となります。説明のために、以下の例は、再生モードに入るときの静的変数のリセットと静的イベントハンドラの登録解除の両方を示しています。ベストプラクティスは、再生モードで静的イベントハンドラを常に登録解除することです。次の再生モードセッションまで待機すると、オブジェクトリファレンスの問題が発生し、誤ったハンドラーの登録解除につながる可能性があります。
Unity には、
UnityEngine
名前空間と
UnityEditor
名前空間の両方にカスタム初期化属性があり、手動ステート リセットなどの初期化作業の実行に使用できます。どの属性を使用するかは、コードが編集モードと再生モードのいずれで実行されているかによって異なります。プレイヤー(ランタイム)スクリプトの再生モードの開始時にステートをリセットするには、
[RuntimeInitializeOnLoadMethod]
属性と
RuntimeInitializeLoadType.SubsystemRegistration
パラメーターを使用します。
using UnityEngine;#if UNITY_EDITORusing UnityEditor;#endifpublic class StateResetOnEnter :MonoBehaviour{ 静的 int counter = 0; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void Init() { Debug.Log("Unregistering handler."); // Unregister the handler so it doesn't affect the next Play mode run EditorApplication.playModeStateChanged -= OnExitPlayMode; Debug.Log("Resetting counter."); // Reset the counter so it starts from 0 on the next Play mode run counter = 0; } void Start() {#if UNITY_EDITOR EditorApplication.playModeStateChanged += OnExitPlayMode;#endif } // Update is called once per frame void Update() { if (Input.anyKeyDown) { counter++; Debug.Log("Counter: " + counter); } }#if UNITY_EDITOR private static void OnExitPlayMode(PlayModeStateChange state) { if(state == PlayModeStateChange.ExitingPlayMode) { Debug.Log("Exiting Play mode!"); } }#endif}
[RuntimeInitializeOnLoadMethod]
は
UnityEngine
名前空間にあるため、再生モードでのみ使用できます。カスタムWindowsや静的なインスペクターなどのエディター専用のスクリプトでは、以下のいずれかを実行できます。
注
前述のコード例では MonoBehaviour クラスを使用していますが、ScriptableObject や独自のカスタム C# 型から継承したものなど、あらゆる種類のスクリプトで初期化属性を使用することもできます。

追加リソース