• Unity3d C# 实现AA包(Addressables)资源热更新的多个包异步加载并显示加载实时进度功能(含源码)


    前言

    该功能的aa包是本地包,我这边项目的需求就是将沙盘的多场景在程序初始化的时候将所有场景实例化,不使用动态加载的方式,必然会造成程序运行的设备的负载加大,不过特定的需求就是在切换场景的过程更丝滑(如不用转圈等待)。
    如果对使用统一可寻址资产系统(Addressables)还不熟悉的,可以查看我之前写的两篇博客:
    Unity3d 使用统一可寻址资产系统(Addressables)入门学习保姆级教程(含工程)
    Unity3d 使用统一可寻址资产系统(Addressables)实现服务器资源热更新和资源版本管理等功能(含源码)

    我这边使用的版本是Unity3d 2020.3.12f1c1 和 Addressables 1.20.0。不同版本会可能会有一定的效果差异。
    #效果
    先来看看最终实现后的效果:
    在这里插入图片描述

    实现功能

    实现过程相对比较简单的就是使用协程StartCoroutine的方式Addressables.LoadAssetAsync()加载资源包 ,资源包采用配置数组的方式进行提前配置,并实例化对象在指定节点下面。AsyncOperationHandle的PercentComplete属性来同步更新每个资源的加载进度,并将进度同步到UI的进度条图片和Text上。

    UI搭建

    UI的搭建较为简单,新建一个图片为进度条,将Image Type设置为Filled,FillMathod 设置为Horizontal,Fill Origin设置为 Left:
    在这里插入图片描述

    这样设置后我们只需要修改Fill Amount就是进度条的进度了。

    然后再新建两个Text作为加载的提示和加载的进度即可:
    在这里插入图片描述

    AA场景包处理

    关于场景包的处理,我这里是对场景的节点进行了拖拽成了预设prefab文件,然后将prefab文件添加到Addressables对应的组中,进行Addressables打包即可,这些操作已经在之前的两篇博客中有详细的介绍,这里就不介绍了。
    要注意的是在Hierarchy窗口中关联的prefab节点要进行删除,为了防止误操作,最好进行版本管理(svn 或者 git)。

    AA包类

    这里我们新建了AA包的配置类如下:

    [System.Serializable]
    public class AAPack
    {
        public string NodeName;
        public Transform ParentTran;
        public Vector3 scale = Vector3.one;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    NodeName为aa包名,在Addressables Groups窗口对应填写的包名:
    在这里插入图片描述

    ParentTran为实例化到该节点的子节点,scale 为实例化后的缩放配置;可以自行添加其他配置项,如实例化的位置(position),实例化的旋转角度(eulerAngles),新增的其它配置项需要在实例化的时候新增对应参数的设置。

    这里的aa包配置,我设置为数组,并将对应的需要加载的包配置如下:

    在这里插入图片描述

    加载AA包

    先贴出加载和更新进度UI的代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.AddressableAssets;
    using UnityEngine.ResourceManagement.AsyncOperations;
    
    public class AAPackLoader : MonoBehaviour
    {
        public AAPack[] AAPacks;
    
        public Image ProcessImg;
        public Text ProcessText;
    
        int NowIdx = 0;
        float TotalRat = 0;
        // Start is called before the first frame update
        void Start()
        {
            transform.localScale = Vector3.one;
            ProcessImg.fillAmount = 0;
            ProcessText.text = "0%"; 
            StartCoroutine(LoadAllAAPack());
        }
    
        AsyncOperationHandle<GameObject> AO;
    
        IEnumerator  LoadAllAAPack() {
            for (int i = 0; i < AAPacks.Length; i++) {
                NowIdx = i;
                if (AAPacks[i] != null)
                {
                    AO = Addressables.LoadAssetAsync<GameObject>(AAPacks[i].NodeName);
                    yield return AO; 
                    if (AO.Status == AsyncOperationStatus.Succeeded)
                    {
                        GameObject go = Instantiate(AO.Result, Vector3.zero, Quaternion.identity); 
                        go.name = AAPacks[i].NodeName;
                        go.transform.SetParent(AAPacks[i].ParentTran == null ? this.transform : AAPacks[i].ParentTran);
                        go.transform.localPosition = Vector3.zero;
                        go.transform.localEulerAngles = Vector3.zero;
                        go.transform.localScale = AAPacks[i].scale;
                        go.SetActive(true);
                    }
                }
            }
            transform.localScale = Vector3.zero;
            Destroy(gameObject);
        }
    
        // Update is called once per frame
        void Update()
        {
            if (AAPacks.Length > 0) {
                   //+1
                TotalRat = (float)(NowIdx) / (float)AAPacks.Length + AO.PercentComplete / AAPacks.Length;   //AO.GetDownloadStatus().Percent
                //Debug.Log("NowIdx:" + NowIdx + " TotalRat:" + TotalRat + "  AAPacks:" + AAPacks.Length + " Percent:" + AO.PercentComplete);
                ProcessImg.fillAmount = TotalRat;
                ProcessText.text = (TotalRat * 100).ToString("F1") + "%";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    这里启动时直接开始了协程IEnumerator LoadAllAAPack进行所有包的加载,并在Update函数中对进度进行了换算和更新。在加载完成后,直接销毁了该对象,因为这个模块在程序启动时,加载了所有的场景,它的工作已经完成了,不会再执行了,所以进行了销毁。

    接下来直接将需要关联的节点拖拽进入对应的框内:
    在这里插入图片描述

    并运行即可。

  • 相关阅读:
    python 基础便利操作
    gitee生成公钥和远程仓库与本地仓库使用验证
    龙测票选,5本最受欢迎的软件测试书籍
    Seaborn数据可视化综合应用Basemap和Seaborn在线闯关_头歌实践教学平台
    HS6621Cx 一款低功耗蓝牙SoC芯片 应用于键盘、鼠标和遥控器消费类产品
    AIE荧光性质温温敏性水凝胶纳米微球PS-co-PNIPAM/银纳米团簇与吡啶羧酸AIE水凝胶的制备
    如何做好漏洞扫描工作提高网络安全
    Genesis公链:夯实Web 3.0发展底座
    矩阵键盘独立接口设计(Keil+Proteus)
    JAVA中的进制与位运算
  • 原文地址:https://blog.csdn.net/qq_33789001/article/details/127490940