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,避免影响下一次运行。
验证流程
- 完成修复后,退出Play模式,确认Hierarchy无残留GameManager。
- 重新进入Play模式,测试场景加载流程,观察是否仍有异常。
- 多次启停Play模式,确认问题不再复现。
内容的提问来源于stack exchange,提问作者SamRose
相关产品推荐
相关产品推荐

