Unity中如何使用单例模式实现跨场景传递CameraRig对象?
CameraRig跨场景单例的代码实现位置方案
核心原则:单例生命周期逻辑要和业务逻辑完全解耦,不要把单例代码混在相机控制、队伍管理的功能脚本里。
具体实现分层
- 第一层(可选,推荐实现):抽一个通用的持久化单例泛型基类,所有需要跨场景存活的MonoBehaviour单例都可以复用这个基类,不用重复写相同的判断逻辑,代码示例如下:
// 这个脚本放在项目专门存通用工具/框架代码的目录即可,和具体业务无关 public class PersistentMonoSingleton<T> : MonoBehaviour where T : Component { public static T Instance { get; private set; } protected virtual void Awake() { // 重复创建实例时直接销毁多余对象 if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; // 标记整个对象跨场景不销毁 DontDestroyOnLoad(gameObject); } }
- 第二层:在你的CameraRig根对象上单独挂载一个轻量脚本,比如命名为
CameraRigRoot,这个脚本只负责托管整个CameraRig对象的单例生命周期,不写任何相机控制、队伍切换的业务逻辑,只需要继承上面的泛型基类即可:
// 这个脚本仅挂在CameraRig根节点,和对象生命周期完全绑定 public class CameraRigRoot : PersistentMonoSingleton<CameraRigRoot> { // 不需要写额外逻辑,基类已经处理完单例判断和跨场景保活 }
- 第三层:你原来写的
CameraController、TeamManager脚本完全不需要改动,保持原有的业务逻辑就行。其他脚本需要调用相机控制、队伍切换功能时,直接通过单例实例拿对应组件即可,比如:
// 其他业务逻辑里的调用示例 CameraController mainCamCtrl = CameraRigRoot.Instance.GetComponent<CameraController>(); TeamManager camTeamMgr = CameraRigRoot.Instance.GetComponent<TeamManager>();
避坑说明
不要把单例逻辑直接写在CameraController或者TeamManager这类业务脚本里:
- 单例的生命周期是和整个CameraRig对象绑定的,不是和某个单独组件绑定的。如果把单例逻辑写在CameraController里,后续你如果需要临时加过场相机、也挂载CameraController组件做控制,会直接触发单例冲突,把原本持久化的主相机Rig销毁,排查问题成本很高。
- 业务逻辑和生命周期逻辑混在一起,后续改功能的时候很容易不小心改坏单例判断逻辑,导致跨场景丢对象、多实例重复创建之类的问题。
简化方案
如果你的项目目前规模很小,只有CameraRig这一个需要跨场景持久化的对象,不想额外抽通用基类,也可以直接把单例判断、DontDestroyOnLoad的逻辑直接写在CameraRigRoot脚本里,不需要泛型基类,功能完全一致。
内容的提问来源于stack exchange,提问作者Pablo Gasamans Losada
相关产品推荐
相关产品推荐

