使用DontDestroyOnLoad()函数时如何访问场景中的其他脚本?
DontDestroyOnLoad 跨场景脚本访问实现方案
首先修正你代码中的基础错误:
- API拼写错误:你写的
Dondestroy不存在,正确接口为DontDestroyOnLoad() - 调用时需保证脚本挂载在场景根物体上,若挂载在父物体下的子物体,会随父物体销毁被清除,无法实现常驻。
核心问题原因
标记了DontDestroyOnLoad的物体是跨场景常驻对象,场景切换时,新场景内的所有物体是在加载流程完成后才完成初始化的,如果你在常驻脚本的Awake/Start生命周期里直接查找场景内脚本,会因为时序问题查找到空引用。
可行实现方案
- 方案1:监听场景加载完成事件,待场景初始化完毕后再查找目标脚本
这是最稳妥的主动查找方案,不会出现时序问题,参考代码:using UnityEngine; using UnityEngine.SceneManagement; public class PersistentNode : MonoBehaviour { // 单例实例,方便其他脚本反向访问常驻物体 public static PersistentNode Instance; private SceneTargetScript _targetScript; void Awake() { // 处理重复常驻的问题 if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; // 正确调用常驻接口 DontDestroyOnLoad(gameObject); // 注册场景加载完成监听 SceneManager.sceneLoaded += OnNewSceneLoaded; } private void OnNewSceneLoaded(Scene scene, LoadSceneMode loadMode) { // 场景加载完成后,所有场景物体已初始化,此时查找不会为空 _targetScript = FindObjectOfType<SceneTargetScript>(); if (_targetScript != null) { // 找到后可直接调用目标脚本的方法、访问属性 _targetScript.BindPersistentNode(this); } } void OnDestroy() { // 销毁时注销监听,避免内存泄漏 SceneManager.sceneLoaded -= OnNewSceneLoaded; } } - 方案2:反向通信,让场景内脚本主动访问常驻对象
这是更解耦的实现方式,不需要常驻物体主动查找场景对象,场景脚本在自身生命周期内主动访问常驻物体的单例即可,参考场景脚本代码:public class SceneTargetScript : MonoBehaviour { void Start() { // 场景脚本初始化时,直接访问常驻物体单例完成通信 if (PersistentNode.Instance != null) { PersistentNode.Instance.RegisterTarget(this); } } } - 方案3:固定引用挂载(不推荐大规模使用)
对于固定位置的核心场景对象,可以在场景加载完成后,通过指定Tag、或者提前挂载引用的方式访问,灵活性较差,仅适合小型项目固定流程使用。
注意事项
- 禁止在常驻物体的
Awake/Start生命周期中直接查找非常驻场景对象,必然会因为加载时序问题返回空 - 不要每帧调用
FindObjectOfType系列接口查找对象,性能开销极高,查找一次后缓存引用即可 - 若常驻物体需要管理多个场景对象,建议搭配事件系统实现通信,减少硬引用依赖
内容的提问来源于stack exchange,提问作者mohsen salim
相关产品推荐
相关产品推荐

