【Unity】 HTFramework框架(五十三)使用 Addressables 可寻址系统

更新日期:2024年7月25日。

Github源码:[点我获取源码]

Gitee源码:[点我获取源码]

索引

  • [Addressables 可寻址系统](#Addressables 可寻址系统)
  • [使用 Addressables 可寻址系统](#使用 Addressables 可寻址系统)

Addressables 可寻址系统

Addressables可寻址系统是迄今为止最完善的Unity资源管理方案,对资源的加载、打包甚至是部署都实现了流水线式的封装。

所以,是时候将Addressables加入到框架的资源加载策略中了。

不过,针对一些小型的项目、小游戏等,我们依然建议使用Resource加载模式或AssetBundle加载模式,因为Addressables会带来一定的资源管理复杂度,会增加维护成本。

使用 Addressables 可寻址系统

在框架中使用Addressables将极其简单,甚至原来使用Resource加载模式或AssetBundle加载模式的代码都不需要做出任何修改,就能直接无缝切换到Addressables模式。

一、导入 Addressables

首先是从包管理器中导入Addressables包,目前框架支持的Addressables版本为1.20.01.30.0之间的任何版本(后续会根据Addressables的版本迭代实时跟进):

二、切换到 Addressables 加载模式

Resource资源管理器模块的加载模式切换为Addressables模式:

三、切换资源加载助手

加载模式切换为Addressables模式后,我们会看到一条红色的错误提示:

DefaultResourceHelper(缺省的资源加载助手)不支持使用 Addressables 模式!

所以我们必须要更换资源加载助手,更换为HT.Framework.AddressablesHelper

它即是缺省的资源加载助手(Addressables 模式)

四、加载资源

此时,我们即可按常规方式加载资源(Main.m_Resource.Load...),在外部调用上,ResourceAssetBundleAddressables三种模式可以没有任何区别。

我们举个例子,将HTFrameworkDemo中的Resource场景切换为Addressables模式。

其原本是使用的AssetBundle模式,旨在演示如何使用AssetBundle加载预制体、材质球、场景等资源。

首先,将加载模式资源管理器助手按上文描述的进行设置:

然后,将需要加载的资源标记为可寻址

再者,运行场景,所有资源就能正确加载了:

是不是极其简单?且能做到代码零修改的无缝切换!

而且,原来的AssetBundle模式使用的是单线加载策略,每一个资源加载时都可能会存在等待时间,也即是等待当前加载的线路完成:

Addressables模式不使用单线加载策略,所以在上上图中我们可以看到加载日志中是没有等待耗时这个参数的。

五、注意事项

我们回看Demo场景中加载资源的代码:

csharp 复制代码
    /// <summary>
    /// 资源测试
    /// </summary>
    public class ResourceTest : MonoBehaviour
    {
        private SceneInfo _scene = new SceneInfo("scene", "Assets/HTFrameworkDemo/Script/Resource/TestScene.unity", "TestScene");
        private PrefabInfo _cube = new PrefabInfo("cube", "Assets/HTFrameworkDemo/Script/Resource/Cube.prefab", null);
        private PrefabInfo _capsule = new PrefabInfo("capsule", "Assets/HTFrameworkDemo/Script/Resource/Capsule.prefab", null);
        private PrefabInfo _sphere = new PrefabInfo("sphere", "Assets/HTFrameworkDemo/Script/Resource/Sphere.prefab", null);
        private AssetInfo _redMat = new AssetInfo("redmat", "Assets/HTFrameworkDemo/Script/Resource/Red.mat", null);
        private List<GameObject> _prefabs = new List<GameObject>();
        private Material _red;

        private void Awake()
        {
            Main.m_Resource.SetAssetBundlePath(Application.dataPath + "/HTFrameworkDemo/Script/Resource/AB/");
        }

        private void Start()
        {
            //加载三个预制体,他们关联的AB包会被自动加载
            Main.m_Resource.LoadPrefab(_cube, null, OnLoading, OnLoadDone);
            Main.m_Resource.LoadPrefab(_capsule, null, OnLoading, OnLoadDone);
            Main.m_Resource.LoadPrefab(_sphere, null, OnLoading, OnLoadDone);
        }

        private void OnGUI()
        {
            if (GUILayout.Button("全部替换为红色材质"))
            {
                StartCoroutine(LoadRedMat());
            }
            if (GUILayout.Button("加载TestScene场景"))
            {
                Main.m_Resource.LoadScene(_scene);
            }
            if (GUILayout.Button("卸载TestScene场景"))
            {
                Main.m_Resource.UnLoadScene(_scene);
            }
            if (GUILayout.Button("卸载所有场景"))
            {
                Main.m_Resource.UnLoadAllScene();
            }
        }
        
        /// <summary>
        /// 加载红色材质
        /// </summary>
        private IEnumerator LoadRedMat()
        {
            yield return null;

            //等待加载完成
            yield return Main.m_Resource.LoadAsset<Material>(_redMat, null, (mat) =>
            {
                Log.Info("加载红色材质完成!");
                _red = mat;
            });

            for (int i = 0; i < _prefabs.Count; i++)
            {
                _prefabs[i].GetComponent<MeshRenderer>().material = _red;
            }
        }

        private void OnLoadDone(GameObject arg)
        {
            Log.Info("加载完成:" + arg.name);

            arg.SetActive(true);
            arg.transform.position = Vector3.zero + new Vector3(0, 0, _prefabs.Count * 2);
            Main.m_Controller.SetLookPoint(arg.transform.position);
            _prefabs.Add(arg);
        }

        private void OnLoading(float arg)
        {
            Log.Info("加载中,进度:" + arg);
        }
    }

为了实现三种加载模式间的无缝切换,Addressables模式加载资源时建议依然传入完整的资源信息对象,比如:

csharp 复制代码
PrefabInfo cube = new PrefabInfo("cube", "Assets/HTFrameworkDemo/Script/Resource/Cube.prefab", "Cube");
Main.m_Resource.LoadPrefab(_cube, null);

在这里,事实上Addressables只关心第二个参数assetPath,它是通过第二个参数去寻址资源的,改成下面这样也能正确加载:

csharp 复制代码
PrefabInfo cube = new PrefabInfo(null, "Assets/HTFrameworkDemo/Script/Resource/Cube.prefab", null);
Main.m_Resource.LoadPrefab(_cube, null);

只不过,为了考虑无缝切换,第一个参数和第三个参数也建议正常传入。

还有就是,资源的寻址Key建议始终设置为其相对路径

这样可以应对大多数变化,且此相对路径永远都是唯一的。

还有一个重点,在缺省的HT.Framework.AddressablesHelper助手中,使用Main.m_Resource.Load...加载任何资源都不会产生引用计数,也即是资源的引用计数特性在这里是无效的,是不需要关心的,因为它有一定的管理复杂性,与我们的宗旨背道而驰(更简洁的代码、更简易的功能、依然能实现我们的需求)。

关于Addressables如何进行资源管理和配置,我这里就不做涉及了,看完下面这篇文章会使你醍醐灌顶:

【游戏开发探究】Unity Addressables资源管理方式

相关推荐
/**书香门第*/42 分钟前
Cocos creator 3.8 支持的动画 7
学习·游戏·游戏引擎·游戏程序·cocos2d
向宇it15 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
Heaphaestus,RC16 小时前
【Unity3D】获取 GameObject 的完整层级结构
unity·c#
芋芋qwq16 小时前
Unity UI射线检测 道具拖拽
ui·unity·游戏引擎
tealcwu17 小时前
【Unity服务】关于Unity LevelPlay的基本情况
unity·游戏引擎
大眼睛姑娘19 小时前
Unity3d场景童话梦幻卡通Q版城镇建筑植物山石3D模型游戏美术素材
unity·游戏美术
鹿野素材屋1 天前
Unity Dots下的动画合批工具:GPU ECS Animation Baker
unity·游戏引擎
小春熙子1 天前
Unity图形学之着色器之间传递参数
unity·游戏引擎·技术美术·着色器
虾球xz1 天前
游戏引擎学习第15天
学习·游戏引擎
Java Fans2 天前
在Unity中实现电梯升降功能的完整指南
unity·游戏引擎