You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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),由它来控制目标脚本的启用时机:

  1. 先在Inspector面板中将目标脚本设置为禁用状态
  2. 场景管理器代码:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:32:18