Unity中DontDestroyOnLoad失效求助:场景切换时对象被销毁
我正在开发一款针对公共场所小区域的GPS应用,地图上的对象代表该区域内的房间位置。我不希望这些对象在切换场景时被销毁,否则需要重新加载到列表中,再从数据库修改它们的名称和颜色。但我无法实现这一点,肯定是哪里操作有误。
我给约300个对象都添加了相同的脚本,代码如下:
private void Awake() { { { DontDestroyOnLoad(this.gameObject); AulaDatabase.addAula(this); } } }
我知道每次进入场景对象都会被添加,但问题是它们总会被销毁。我还尝试给所有这些对象的父容器添加另一个脚本,也没有效果。需要说明的是,我在其他对象上使用DontDestroyOnLoad是有效的,请问我哪里做错了?
核心问题分析
你遇到的问题不是DontDestroyOnLoad本身失效,而是场景切换时重复加载了房间对象,新加载的对象可能触发了某种逻辑导致旧对象被销毁,或者你没做去重,误以为原来的对象被销毁了。另外你代码里的多层嵌套大括号是冗余的,虽然不影响语法,但可以删掉。
具体修复步骤
给房间对象加唯一标识并做去重
给每个房间对象分配一个唯一ID(比如从数据库获取的房间编号),在Awake里先检查数据库中是否已存在该对象,避免重复加载:public string roomId; // 在Inspector面板或从数据库赋值唯一ID private void Awake() { // 检查数据库中是否已有同ID的房间实例 if (AulaDatabase.HasAula(roomId)) { Destroy(this.gameObject); // 销毁重复加载的对象 return; } DontDestroyOnLoad(this.gameObject); AulaDatabase.AddAula(roomId, this); // 改用ID作为键存储,方便校验 }用父容器单例统一管理(更适合批量对象)
之前给父容器加脚本没效果,大概率是没做单例去重。正确的父容器脚本写法如下:- 将所有房间对象放到一个空物体(命名为
RoomContainer)下 - 给
RoomContainer添加以下脚本:public class RoomContainer : MonoBehaviour { private static RoomContainer _instance; private void Awake() { // 单例校验,避免重复加载父容器 if (_instance != null && _instance != this) { Destroy(this.gameObject); return; } _instance = this; DontDestroyOnLoad(this.gameObject); // 批量注册子房间对象到数据库(做去重) foreach (var roomScript in GetComponentsInChildren<YourRoomScript>()) { if (!AulaDatabase.HasAula(roomScript.roomId)) { AulaDatabase.AddAula(roomScript.roomId, roomScript); } } } }
父容器成为单例后,场景切换时不会被销毁,子房间对象会跟着保留,同时避免重复加载整个容器。
- 将所有房间对象放到一个空物体(命名为
检查场景加载与对象状态
切换场景后,在Unity编辑器的Hierarchy面板里找DontDestroyOnLoad根节点,看看你的房间对象是否在里面:- 如果不在,说明
Awake方法没执行到——检查脚本是否正确挂载,或者对象是否在Awake前被其他逻辑销毁 - 如果在,但你还是看不到,可能是新场景的相机设置问题,或者对象被误设为隐藏
- 如果不在,说明
排查数据库逻辑
检查AulaDatabase.addAula方法,看看里面有没有不小心销毁旧对象、移除实例的代码,这也可能导致你误以为对象被场景切换销毁了。
内容的提问来源于stack exchange,提问作者Arrow

