更新日期:2024年7月25日。
Github源码:[点我获取源码]
Gitee源码:[点我获取源码]
索引
- [Addressables 可寻址系统](#Addressables 可寻址系统)
- [使用 Addressables 可寻址系统](#使用 Addressables 可寻址系统)
-
- [一、导入 Addressables](#一、导入 Addressables)
- [二、切换到 Addressables 加载模式](#二、切换到 Addressables 加载模式)
- 三、切换资源加载助手
- 四、加载资源
- 五、注意事项
Addressables 可寻址系统
Addressables
可寻址系统是迄今为止最完善的Unity资源管理方案,对资源的加载、打包甚至是部署都实现了流水线式的封装。
所以,是时候将Addressables
加入到框架的资源加载策略中了。
不过,针对一些小型的项目、小游戏等,我们依然建议使用Resource
加载模式或AssetBundle
加载模式,因为Addressables
会带来一定的资源管理复杂度,会增加维护成本。
使用 Addressables 可寻址系统
在框架中使用Addressables
将极其简单,甚至原来使用Resource
加载模式或AssetBundle
加载模式的代码都不需要做出任何修改,就能直接无缝切换到Addressables
模式。
一、导入 Addressables
首先是从包管理器中导入Addressables
包,目前框架支持的Addressables
版本为1.20.0
至1.30.0
之间的任何版本(后续会根据Addressables
的版本迭代实时跟进):
二、切换到 Addressables 加载模式
将Resource
资源管理器模块的加载模式切换为Addressables
模式:
三、切换资源加载助手
加载模式切换为Addressables
模式后,我们会看到一条红色的错误提示:
DefaultResourceHelper(缺省的资源加载助手)不支持使用 Addressables 模式!
所以我们必须要更换资源加载助手
,更换为HT.Framework.AddressablesHelper
:
它即是缺省的资源加载助手(Addressables 模式)
。
四、加载资源
此时,我们即可按常规方式加载资源(Main.m_Resource.Load...
),在外部调用上,Resource
、AssetBundle
、Addressables
三种模式可以没有任何区别。
我们举个例子,将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
如何进行资源管理和配置,我这里就不做涉及了,看完下面这篇文章会使你醍醐灌顶: