Version: 6000.3
语言: 中文
配置 Unity 进入播放模式的方式
进入播放模式,禁用场景重新加载

进入禁用域重新加载的游戏模式

脚本域,也称为应用程序域,或简称为域,是 Unity 托管脚本环境的核心功能。域是专用于特定应用程序的独立内存部分,其中包含应用程序所需的编译类型,这些类型分组到称为程序集的逻辑单元中。它还包含表示当前应用程序状态的数据,例如托管内存各个部分中的变量和对象引用的值。

默认情况下,Unity 会在进入 Play 模式时重新加载域以重置应用程序状态。通常需要在进入播放模式之前重置状态,以便应用程序像在新生成开始时一样启动。例如,在上一个运行模式会话中递增的静态计数器应在下一个会话中再次从零开始。但是,域重新加载也是一项耗时的作,当您经常在编辑和播放模式之间切换时,它会对迭代时间产生负面影响。为了加快迭代时间,可以在进入播放模式时禁用域重新加载,但必须在代码中手动重置状态

注意:当 Unity 检测到对脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间修改组件属性以及以您喜欢的任何方式响应用户输入。更多信息
请参阅术语表
.即使禁用了进入播放模式时的域重新加载,这种情况仍然会发生。有关资产数据库刷新的时间和方式的更多信息,请参阅刷新资产数据库

进入游戏模式时禁用域重新加载的影响

禁用域重新加载时:

  • 非序列化字段在返回编辑模式时保留在播放模式下分配给它们的值。这适用于所有脚本类型的字段,包括 MonoBehaviours(包括预制件资产上的字段)、ScriptableObjects 和您自己的自定义 C# 类型。有关在不同上下文中序列化和未序列化的详细信息,请参阅序列化规则
  • 静态变量在播放模式会话之间保留其值。
  • 静态事件会在播放模式会话之间保留其注册订阅者。
  • 没有额外的OnDisableOnEnable调用标有[ExecuteInEditMode][ExecuteAlways].

若要补偿 Play 模式会话之间的这种数据持久性,并以新的应用程序状态进入 Play 模式,必须在代码中重置状态

有关禁用域和场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表
reload,请参阅禁用域和场景重新加载的详细信息

从代码重置状态

禁用域重新加载后,静态字段的值和分配给静态事件的处理程序将在播放模式运行之间保留。以下代码示例有一个静态计数器,该计数器在按下任何键盘键时递增。该代码还注册了一个方法来处理静态事件EditorApplication.playModeStateChanged.

启用域重新加载后,Unity 会在进入 Play 模式时重新初始化此代码,擦除上一次 Play 模式运行中的状态,包括计数器值和事件处理程序的注册。禁用域重新加载后,计数器值和事件处理程序注册都将保留上次运行。在下一次运行播放模式时,计数器从上一次运行结束时的值开始,并在一次事件出现时多次调用事件处理程序方法,从而在控制台中生成多个“正在退出播放模式!

// 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_EDITOR
using UnityEditor;
#endif

public class StateResetExample : MonoBehaviour
{
    // With domain reload disabled this counter won't reset to zero on exiting Play mode
    static 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枚举值来捕获 Play 模式退出事件并重置该点的状态。在以下示例中,Play 模式退出的事件处理程序用于注销自身,但此时您也可以使用此方法注销任何其他静态事件处理程序:

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class StateResetOnExit : MonoBehaviour
{
    static 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.playModeStateChangedUnityEditor命名空间,因此它只能在 Unity 编辑器中的 Play 模式下工作,而不适用于独立的 Player 版本。

如果代码在“播放”模式下执行,则在退出“播放”模式时不能依赖重置状态。你的代码可能会在编辑模式下修改静态变量,因此你必须在进入播放模式时重置该变量。

注意:对于在编辑模式下执行的脚本,禁用域重新加载会跳过MonoBehaviour.OnDisable和禁用场景重新加载跳过MonoBehaviour.OnDestroy,这使得这些方法不适合在此类脚本中重置状态。有关更多信息,请参阅禁用域和场景重新加载的详细信息

进入播放模式时重置状态

您还可以在进入播放模式时重置状态。如果你在捕获退出的播放模式事件时遇到任何特定于平台的问题,或者你的代码也在编辑模式下执行,这可能是一个有用的替代方法。为了说明起见,以下示例演示了在进入播放模式时重置静态变量和取消注册静态事件处理程序。最佳做法是在退出播放模式时始终注销静态事件处理程序。等到下一个播放模式会话可能会导致对象引用问题,从而导致取消注册错误的处理程序。

Unity 在UnityEngineUnityEditor命名空间,可用于执行初始化工作,包括手动状态重置。应使用哪些属性取决于代码是在编辑模式还是播放模式下运行。要重置播放器(运行时)脚本进入播放模式时的状态,可以使用[RuntimeInitializeOnLoadMethod]属性与RuntimeInitializeLoadType.SubsystemRegistration参数:

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class StateResetOnEnter : MonoBehaviour
{
    static 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命名空间,因此它仅在 Play 模式下可用。对于仅限编辑器的脚本,例如自定义编辑器窗口或检查器一个 Unity 窗口,显示有关当前选定游戏对象、资产或项目设置的信息,允许您检查和编辑值。更多信息
请参阅术语表
使用静态的,您可以执行以下作之一:

注意:虽然前面的代码示例使用 MonoBehaviour 类,但您也可以在任何类型的脚本上使用这些初始化属性,包括继承自 ScriptableObject 或您自己的自定义 C# 类型的脚本。

其他资源

配置 Unity 进入播放模式的方式
进入播放模式,禁用场景重新加载