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

相关推荐
超龄魔法少女8 小时前
[Unity] ShaderGraph动态修改Keyword Enum,实现不同效果一键切换
unity·技术美术·shadergraph
蔗理苦9 小时前
2024-12-24 NO1. XR Interaction ToolKit 环境配置
unity·quest3·xr toolkit
花生糖@9 小时前
Android XR 应用程序开发 | 从 Unity 6 开发准备到应用程序构建的步骤
android·unity·xr·android xr
向宇it9 小时前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
虾球xz10 小时前
游戏引擎学习第55天
学习·游戏引擎
虾球xz12 小时前
游戏引擎学习第58天
学习·游戏引擎
ue星空13 小时前
虚幻引擎结构之UWorld
游戏引擎·虚幻
ue星空13 小时前
虚幻引擎结构之ULevel
游戏引擎·虚幻
向宇it14 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
神洛华16 小时前
Y3地图制作1:水果缤纷乐、密室逃脱
编辑器·游戏引擎·游戏程序