Unity场景重载时避免重复对象并控制脚本启停的方法
问题
我正在开发一款多场景的Unity 2D游戏,现需添加重启按钮。我使用DontDestroyOnLoad(gameObject);代码实现玩家在场景切换时不被销毁;使用以下代码重载所有场景:
int currentSceneIndex = SceneManager.GetActiveScene().buildIndex; // Reload all scenes for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++) { SceneManager.LoadScene(i, LoadSceneMode.Single); } // Load the scene that was active before restart SceneManager.LoadScene(currentSceneIndex); SceneManager.LoadScene("floor1", LoadSceneMode.Additive); SceneManager.LoadScene("starter scene", LoadSceneMode.Additive);
当禁用包含DontDestroyOnLoad函数的脚本组件时,单场景运行正常。我的问题是:如何让该脚本在场景加载时保持禁用状态,游戏运行时保持启用状态?
解决方法
方案一:脚本内部自控制状态
在目标脚本中添加场景加载监听,初始化时先禁用自身,等场景加载完成后再启用:
private void Awake() { // 场景加载阶段先禁用脚本 this.enabled = false; DontDestroyOnLoad(gameObject); // 监听场景加载完成事件 SceneManager.sceneLoaded += OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // 场景加载完成后启用脚本 this.enabled = true; } private void OnDestroy() { // 移除监听防止内存泄漏 SceneManager.sceneLoaded -= OnSceneLoaded; }
这种方式让脚本自己管理状态,无需额外外部控制,逻辑直接闭环。
方案二:外部管理器控制状态
创建一个全局场景管理脚本(同样设置DontDestroyOnLoad),由它来控制目标脚本的启用时机:
- 先在Inspector面板中将目标脚本设置为禁用状态
- 场景管理器代码:
public class SceneLoader : MonoBehaviour { public YourTargetScript targetScript; // 在Inspector中拖入目标脚本组件 private void Awake() { DontDestroyOnLoad(gameObject); SceneManager.sceneLoaded += OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // 所有场景加载完成后启用目标脚本 if(targetScript != null) targetScript.enabled = true; } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; } }
该方案把控制逻辑和业务脚本分离,适合多脚本协同的复杂场景。
额外优化:修复当前重启逻辑的问题
你现有的场景重载代码存在逻辑错误:用LoadSceneMode.Single循环加载场景时,每次加载都会卸载之前的场景,最终只会保留最后一次加载的场景。正确的重启流程应该是先卸载所有非持久化场景,再重新加载目标场景:
public void RestartGame() { int currentSceneIndex = SceneManager.GetActiveScene().buildIndex; // 卸载所有已加载的非持久化场景 for (int i = 0; i < SceneManager.sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); if (scene.isLoaded && !scene.name.Equals("PersistentScene")) // 替换为你的持久化场景名称 { SceneManager.UnloadSceneAsync(scene); } } // 等待卸载完成后再加载场景 StartCoroutine(LoadTargetScenes(currentSceneIndex)); } private IEnumerator LoadTargetScenes(int targetIndex) { // 等待所有非持久化场景卸载完毕 yield return new WaitUntil(() => SceneManager.sceneCount == 1); // 加载主场景和附加场景 SceneManager.LoadScene(targetIndex); yield return null; // 等待主场景加载完成 SceneManager.LoadScene("floor1", LoadSceneMode.Additive); SceneManager.LoadScene("starter scene", LoadSceneMode.Additive); }
内容的提问来源于stack exchange,提问作者Kamalesh D
相关产品推荐
相关产品推荐

