DontDestroyOnLoad脚本场景切换后PlayerSpriteRenderer值为null问题
问题根源
场景切换时,原场景内的Player对象会被Unity自动销毁,你存在DontDestroyOnLoad标记的GameManager里的activeRendererGameManager是对旧Player的Renderer引用,自然会变成null。而int是值类型,直接存储在GameManager的内存空间中,不受场景对象销毁的影响,所以能正常保留。
解决方法
1. 保存Renderer的状态数据而非引用
不要直接存储Renderer对象,提取你需要的具体状态(比如Sprite、材质、颜色)存在GameManager中,等新场景加载完成后,找到新场景里的Player,把保存的状态赋值给它:
// 在LevelCompleteSequence中保存Player的Sprite public void SavePlayerSprite() { SpriteRenderer playerRenderer = player.GetComponent<SpriteRenderer>(); GameManager.Instance.savedPlayerSprite = playerRenderer.sprite; // 如果需要颜色也保存:GameManager.Instance.savedPlayerColor = playerRenderer.color; } // 新场景加载完成后为Player赋值 public void ApplyPlayerSprite() { Player newPlayer = FindObjectOfType<Player>(); if (newPlayer != null) { SpriteRenderer newRenderer = newPlayer.GetComponent<SpriteRenderer>(); newRenderer.sprite = GameManager.Instance.savedPlayerSprite; // 若保存了颜色:newRenderer.color = GameManager.Instance.savedPlayerColor; } }
2. 让Player对象跨场景保留
如果需要整个Player对象不被销毁,给Player也加上DontDestroyOnLoad,同时处理重复实例问题(避免新场景加载后出现多个Player):
// Player脚本的Awake方法 private void Awake() { DontDestroyOnLoad(gameObject); // 检查是否已有存在的Player实例 Player[] existingPlayers = FindObjectsOfType<Player>(); if (existingPlayers.Length > 1) { Destroy(gameObject); } }
这样GameManager里的Renderer引用会一直指向这个不被销毁的Player,不会出现null的情况。
3. 用场景加载回调替代Invoke
Invoke的延迟时间不可靠,改用Unity官方的场景加载完成回调,确保场景完全加载后再执行Player状态恢复:
// 替换原来的LoadLevel + Invoke代码 public void LoadNextLevel() { SceneManager.LoadScene("目标场景名"); SceneManager.sceneLoaded += OnSceneLoaded; } // 场景加载完成的回调方法 private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { ApplyPlayerSprite(); // 就是上面的状态恢复方法 SceneManager.sceneLoaded -= OnSceneLoaded; // 移除回调防止重复触发 }
这样就不会出现因场景未加载完成找不到Player的报错。
内容的提问来源于stack exchange,提问作者Blinkz
相关产品推荐
相关产品推荐

