unity DontDestroyOnLoad遇到的坑

Unity3D的DontDestoryOnLoad API可避免场景切换时对象被删除。但使用中会出现对象数量递增问题,如场景A中的对象o,切换场景再返回,对象o数量会不断增加,作者采用静态bool进行判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Unity3D提供了一个不删除前一个场景中的某一个对象或者脚本的API——DontDestoryOnLoad(对象或者某个脚本)。

它是为了在游戏开发中可以创建多个场景,但又不会因为场景过度而删除对象。

但是我们在用这个API的时候我们会发现一个很奇怪的问题就是:如果A里面放了个东西o,当到场景B的时候,o 也会出现在B场景中,这里一看,感觉还是对的,然后你再返回到场景A, 你就会惊讶的发现,A里面出现了两个o,然后你到B,看到B里面也出现了两个o, 再回到A, A里面出现了3个o, 一直递增上去。

我这里用了一个静态的 bool 来判断

public static class SeverDate
{
    public static bool isDontDestory = true;
}

private void Awake()
{

    if (SeverDate.isDontDestory)
    {
        DontDestroyOnLoad(gameObject);
        SeverDate.isDontDestory = false;
    }
}

 

### Unity 中 `DontDestroyOnLoad` 的用法及常见问题 在 Unity 中,`DontDestroyOnLoad` 是一个非常重要的方法,用于确保某些游戏对象(GameObject)在场景切换时不会被销毁。默认情况下,当从一个场景切换到另一个场景时,所有当前场景中的对象都会被销毁,并加载新场景中的对象。然而,有些对象可能需要在整个游戏过程中保持存在,例如全局管理器、背景音乐播放器等。这时可以使用 `DontDestroyOnLoad` 方法来实现这一需求[^1]。 以下是关于 `DontDestroyOnLoad` 的详细说明和示例代码: #### 1. 基本用法 通过调用 `Object.DontDestroyOnLoad` 方法,可以将指定的游戏对象或组件标记为“不随场景销毁”。以下是一个简单的示例,展示如何使用该方法保留一个全局管理器对象: ```csharp using UnityEngine; public class PersistentManager : MonoBehaviour { void Start() { // 确保此对象在场景切换时不被销毁 DontDestroyOnLoad(gameObject); } } ``` 在此示例中,`PersistentManager` 对象将在整个游戏生命周期内保持存在,即使场景发生切换也不会被销毁。 #### 2. 注意事项 - **避免重复实例化**:如果多个场景中都有类似的持久化对象,可能会导致重复实例化的问题。为了解决这个问题,通常会结合单例模式使用 `DontDestroyOnLoad`。以下是一个改进的单例实现示例: ```csharp using UnityEngine; public class SingletonManager : MonoBehaviour { private static SingletonManager _instance; public static SingletonManager Instance { get { if (_instance == null) { _instance = FindObjectOfType<SingletonManager>(); if (_instance == null) { GameObject obj = new GameObject("SingletonManager"); _instance = obj.AddComponent<SingletonManager>(); } } return _instance; } } void Awake() { if (_instance == null) { _instance = this; DontDestroyOnLoad(gameObject); } else if (_instance != this) { Destroy(gameObject); } } } ``` 在这个例子中,`SingletonManager` 类确保了只有唯一的一个实例存在,并且该实例在场景切换时不会被销毁[^2]。 #### 3. 常见问题与解决方案 - **内存泄漏问题**:如果使用 `DontDestroyOnLoad` 的对象引用了大量资源(如纹理、音频等),并且这些资源没有被正确释放,可能会导致内存占用过高。因此,在设计持久化对象时,应尽量减少对大资源的直接引用[^1]。 - **跨场景通信问题**:有时需要在不同场景之间传递数据或事件通知。可以结合消息系统(如 `CSharpMessenger Extended` 或自定义的通知中心)来实现跨场景通信。例如,使用以下方式发送通知: ```csharp NotificationCenter.DefaultCenter().PostNotification(this, "SceneChanged"); ``` 需要注意的是,如果消息接收方已经被销毁,可能会引发 `MissingReferenceException` 异常。可以通过捕获异常或检查对象状态来避免此类问题[^3]。 #### 4. 示例场景 假设有一个背景音乐管理器,希望在所有场景中持续播放音乐,可以这样实现: ```csharp using UnityEngine; public class BackgroundMusicManager : MonoBehaviour { private static BackgroundMusicManager _instance; public static BackgroundMusicManager Instance { get { return _instance; } } void Awake() { if (_instance == null) { _instance = this; DontDestroyOnLoad(gameObject); } else if (_instance != this) { Destroy(gameObject); } } public void PlayMusic(AudioClip clip) { GetComponent<AudioSource>().clip = clip; GetComponent<AudioSource>().Play(); } } ``` 在这个例子中,`BackgroundMusicManager` 对象会在所有场景中保持存在,并提供播放背景音乐的功能[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘长长长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值