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

Unity如何在场景加载后、Awake/OnEnable前调用函数?

解决方案

最优方案:异步加载+控制场景激活时机

这是最可靠且无需重复配置的方法,利用Unity异步加载的特性,在场景资源加载完成但未激活时执行存档加载,确保逻辑优先于所有对象的Awake和OnEnable:

using System.Threading.Tasks;
using UnityEngine.SceneManagement;

public class SceneLoader : MonoBehaviour
{
    private SaveSystemManager saveSystemManager;

    private void Awake()
    {
        saveSystemManager = GetComponent<SaveSystemManager>();
        // 标记为 DontDestroyOnLoad,跨场景保留
        DontDestroyOnLoad(gameObject);
    }

    public async void LoadTargetScene(int sceneIndex, LevelLoadParameters levelLoadParamaters)
    {
        // 加载前存档(如果需要)
        if (levelLoadParamaters.saveGameDataBeforeLoad)
        {
            saveSystemManager.Save();
        }

        // 异步加载场景,暂停激活流程
        AsyncOperation loadOperation = SceneManager.LoadSceneAsync(sceneIndex);
        loadOperation.allowSceneActivation = false;

        // 等待资源加载完成(进度到0.9f是Unity异步加载的临界点,代表资源已全部加载)
        while (loadOperation.progress < 0.9f)
        {
            await Task.Yield();
        }

        // 执行存档加载逻辑,此时新场景对象已加载但未激活,Awake/OnEnable尚未触发
        if (levelLoadParamaters.loadGameDataAfterLoad)
        {
            saveSystemManager.Load();
        }

        // 激活场景,触发所有对象的Awake/OnEnable
        loadOperation.allowSceneActivation = true;
    }
}

关键逻辑说明

  • allowSceneActivation = false会让场景加载停在资源加载完成的阶段,此时新场景的所有对象已存在于内存,但未被激活,Awake和OnEnable不会执行。
  • 进度到0.9f是Unity的内置机制,代表场景资源已全部加载完成,剩下的10%进度对应场景激活步骤。
  • 执行完存档加载后再激活场景,就能保证所有对象的初始化逻辑基于最新的存档数据。

备选方案:全局初始化管理器+脚本执行顺序

如果不想用异步加载,可以创建一个全局的初始化管理器:

  1. 创建一个空对象,添加初始化脚本,标记为DontDestroyOnLoad。
  2. 在Project Settings -> Script Execution Order中,将该脚本的执行顺序设为所有脚本的最顶端(数值越小越先执行)。
  3. 在脚本的Awake方法中监听SceneManager.activeSceneChanged事件,当场景切换完成后立即执行存档加载:
using UnityEngine.SceneManagement;

public class GlobalInitializer : MonoBehaviour
{
    private SaveSystemManager saveSystemManager;
    private LevelLoadParameters currentLoadParams;

    private void Awake()
    {
        saveSystemManager = GetComponent<SaveSystemManager>();
        DontDestroyOnLoad(gameObject);
        SceneManager.activeSceneChanged += OnSceneChanged;
    }

    // 调用此方法触发场景加载
    public void StartSceneLoad(int sceneIndex, LevelLoadParameters parameters)
    {
        currentLoadParams = parameters;
        if (currentLoadParams.saveGameDataBeforeLoad)
        {
            saveSystemManager.Save();
        }
        SceneManager.LoadScene(sceneIndex);
    }

    private void OnSceneChanged(Scene oldScene, Scene newScene)
    {
        if (currentLoadParams?.loadGameDataAfterLoad ?? false)
        {
            saveSystemManager.Load();
            currentLoadParams = null;
        }
    }
}

这个方案的核心是利用脚本执行顺序,让全局管理器的Awake(以及事件回调)优先于场景内其他对象的Awake执行。

内容的提问来源于stack exchange,提问作者Jay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 15:13:11