【Unity开发】避免重复加载场景资产AB(AssetBundle)包的优化

@[TOC](【Unity开发】避免重复加载场景资产AB(AssetBundle)包的优化)

项目需要远程加载场景AB包,并加载场景。

1、 初始方案

1.1 异步加载场景资产(获取AB包数据)

	public IEnumerator LoadAssetFromAB(string url, Action<AssetBundle> assetAB)
    {
        yield return new WaitForSeconds(0.16f);
        using (UnityWebRequest webRequest = UnityWebRequestAssetBundle.GetAssetBundle(url))
        {
            yield return webRequest.SendWebRequest();
            if (webRequest.result == UnityWebRequest.Result.Success){
                    var bundle = DownloadHandlerAssetBundle.GetContent(webRequest);
                    assetAB?.Invoke(bundle);
            }
        }
    }

1.2 异步加载场景(进入场景)

	// 异步加载远程AB场景
    public void LoadSceneFromAB(AssetBundle assetAB, string sceneName){
        // 启动异步线程加载场景
        StartCoroutine(AssetToScene(assetAB, sceneName));
    }

    // 异步远程AB场景迭代器
    private IEnumerator AssetToScene(AssetBundle assetAB, string sceneName){
        // 异步加载场景资产
        AsyncOperation  loadOperation = SceneManager.LoadSceneAsync(sceneName);
        yield return loadOperation;

        Debug.Log("应该到不了这里就直接转场了,那么AB资产包还在内存,下次就会报[重复加载]的异常");
        // 卸载内存中的assetAB资产(除了LoadScene创建出来的场景)
        assetAB.Unload(false);
    }

1.3 点击跳转场景

	public void GotoScene(ClickEvent evt){
            string sceneName = "myScene";
            char dsp = Path.AltDirectorySeparatorChar;
            string url = Application.dataPath + dsp + "scene" + dsp + sceneName;

            // 销毁所有未使用资产
            Resources.UnloadUnusedAssets();

            // 临时解决方案
            // 尝试直接加载AB场景 (避免AB资产已在内存时AB包重复报错)
            // The AssetBundle 'http://192.168.2.107:8080/level/Level1' can't be loaded because another AssetBundle with the same files is already loaded.
            SceneManager.LoadScene(sceneName);
            // 这里如果成功加载场景,不会走到下一步,
            // 前提是内存里有场景包 1、上次已经加载到内存没卸载 2、程序Build编译时Scenes In Build
            // Scene 'Level1' couldn't be loaded because it has not been added to the build settings or the AssetBundle has not been loaded.
			//To add a scene to the build settings use the menu File->Build Settings...

            // 远程异步加载AB场景资产
            StartCoroutine(_dataRestapi.LoadAssetFromAB(url, (assetAB) => {
                if (assetAB != null) {
                    LoadSceneFromAB(assetAB, sceneName);
                }else{
                    Debug.LogWarning("场景资产数据加载失败");
                }
            }));
    }

2、 优化方案

2.1 异步加载场景资产(获取AB包数据)

	public IEnumerator LoadAssetFromAB(string url, Action<AssetBundle> assetAB)
    {
        yield return new WaitForSeconds(0.16f);
        using (UnityWebRequest webRequest = UnityWebRequestAssetBundle.GetAssetBundle(url))
        {
            yield return webRequest.SendWebRequest();
            if (webRequest.result == UnityWebRequest.Result.Success){
                    var bundle = DownloadHandlerAssetBundle.GetContent(webRequest);
                    assetAB?.Invoke(bundle);
            }
        }
    }

2.2 异步加载场景(进入场景)

1 注册后处理事件 SceneManager.sceneLoaded += OnSceneLoaded;
2 删除永远不会被运行的 assetAB.Unload(false);

	// 异步加载远程AB场景
    public void LoadSceneFromAB(AssetBundle assetAB, string sceneName){
        // 启动异步线程加载场景
        StartCoroutine(AssetToScene(assetAB, sceneName));
        // 当新场景开始加载时注册事件 解决加载完成后处理事件
        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    // 异步远程AB场景迭代器
    private IEnumerator AssetToScene(AssetBundle assetAB, string sceneName){
        // 异步加载场景资产
        AsyncOperation  loadOperation = SceneManager.LoadSceneAsync(sceneName);
        yield return loadOperation;
    }

2.3 点击跳转场景

删除尝试加载场景 SceneManager.LoadScene(sceneName);
因为不需要了,每次运行都是从远程获取最新的场景AB包

	public void GotoScene(ClickEvent evt){
            string sceneName = "myScene";
            char dsp = Path.AltDirectorySeparatorChar;
            string url = Application.dataPath + dsp + "scene" + dsp + sceneName;

            // 销毁所有未使用资产
            Resources.UnloadUnusedAssets();

            // 远程异步加载AB场景资产
            StartCoroutine(_dataRestapi.LoadAssetFromAB(url, (assetAB) => {
                if (assetAB != null) {
                    LoadSceneFromAB(assetAB, sceneName);
                }else{
                    Debug.LogWarning("场景资产数据加载失败");
                }
            }));
    }

2.4 增加场景加载后处理事件

保证场景加载完成后自动删除场景AB资产包

	// 场景加载后处理事件
    void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        // 当新场景加载完成后,卸载内存中AssetBundle包(除了Load创建出来的对象/场景)
        _assetAB.Unload(false);

        // 注销事件,防止重复调用
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值