【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资源管理方式

相关推荐
逐·風2 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i3 小时前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
代码盗圣7 小时前
GODOT 4 不用scons编译cpp扩展的方法
游戏引擎·godot
Leoysq12 小时前
【UGUI】实现点击注册按钮跳转游戏场景
游戏·unity·游戏引擎·ugui
PandaQue14 小时前
《潜行者2切尔诺贝利之心》游戏引擎介绍
游戏引擎
_oP_i15 小时前
unity中 骨骼、纹理和材质关系
unity·游戏引擎·材质
Padid1 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
Tp_jh1 天前
推荐一款非常好用的C/C++在线编译器
linux·c语言·c++·ide·单片机·unity·云原生
dangoxiba1 天前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十八集补充:制作空洞骑士独有的EventSystem和InputModule
游戏·unity·c#·游戏引擎·playmaker
无敌最俊朗@2 天前
unity3d————屏幕坐标,GUI坐标,世界坐标的基础注意点
开发语言·学习·unity·c#·游戏引擎