You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity 2022.3.8f1:DontDestroyOnLoad的GameManager仅首次编译可Spawn玩家

问题分析与解决方案

核心原因

你遇到的问题本质是:退出Play模式时,Unity会销毁所有标记DontDestroyOnLoad的对象,但如果GameManager未正确移除SceneManager.sceneLoaded事件监听器,已销毁的旧实例回调会残留;第二次进入Play模式时,新场景加载事件会触发旧实例的回调,而旧实例已被销毁,从而抛出MissingReferenceException。同时,DontDestroyOnLoad放在Start方法中的初始化时机,也可能加剧引用异常问题。


具体修复步骤

1. 用单例模式确保GameManager唯一

在Awake中实现单例逻辑(比Start更可靠),避免重复实例,同时处理DontDestroyOnLoad:

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    private void Awake()
    {
        // 单例校验:若已有实例,销毁当前对象
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }

        Instance = this;
        DontDestroyOnLoad(gameObject);
    }

    // ... 其他业务代码
}

2. 正确管理SceneLoaded事件监听器

用OnEnable/OnDisable绑定/解绑事件,确保对象销毁(如退出Play模式)时自动移除监听器,避免残留回调:

private void OnEnable()
{
    SceneManager.sceneLoaded += OnSceneLoaded;
}

private void OnDisable()
{
    SceneManager.sceneLoaded -= OnSceneLoaded;
}

3. 替换Invoke为更可靠的调用方式

Invoke依赖MonoBehaviour实例引用,状态异常时易出问题,推荐用协程替代:

// 替换原Invoke代码
StartCoroutine(SpawnAfterDelay(0.2f));

// 新增协程方法
private IEnumerator SpawnAfterDelay(float delay)
{
    yield return new WaitForSeconds(delay);
    InvoSpawn();
}

如果必须保留Invoke,调用前需校验实例有效性:

if (this != null && !gameObject.scene.isLoaded)
{
    Invoke("InvoSpawn", 0.2f);
}

4. 清理编辑器残留对象

退出Play模式后,检查Hierarchy中的DontDestroyOnLoad节点(Unity会将此类对象单独存放),手动删除残留的GameManager,避免影响下一次运行。


验证流程

  1. 完成修复后,退出Play模式,确认Hierarchy无残留GameManager。
  2. 重新进入Play模式,测试场景加载流程,观察是否仍有异常。
  3. 多次启停Play模式,确认问题不再复现。

内容的提问来源于stack exchange,提问作者SamRose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 15:41:10