你好,我是跟着大智学Unity的萌新,我叫小新,这是我本周的学习总结报告哦。
大智:“小新,这周学习有没有遇到什么问题呢?”
小新:“确实遇到了,那个Addressables.LoadAssetsAsync
API,我有一次怎么都加载不出来资源,倒腾了半天,最后发现是参数传的不对。。。”
大智:“那你现在搞明白了没?”
小新:“基本搞明白了。。。”
大智:“那你把Addressable中的加载API总结一下吧~我看看你到底搞明白了没。”
小新:“好嘞。”
Addressable系统的加载资源API
Addressable中加载资源主要有两个途径:
- 通过AssetReference加载
- 使用Addressables类中的静态方法通过地址/Label加载
1.AssetReference加载的API
使用AssetReference
类访问Addressable资产时无需知道他们的地址字符串,但是需要在Inspector上关联。使用流程如下:
- 新建一个脚本,任何可序列化的组件都支持
AssetReference
变量(例如,继承MonoBehaviour的脚本,ScriptableObject或其他可序列化的类)。 - 在组件中添加一个
AssetReference
类型的公共变量(例如public AssetReference explosion;
)。 - 在Inspector中,将资产从“ Project”窗口拖到
AssetReference
字段上(非Addressable资产也可以拖,会自动标记为Addressable),或从项目中已经设置的可寻址资产的下拉列表中进行选择(如下所示)。
要加载或实例化AssetReference
资产,需要调用其相应的方法。例如:
仅加载到内存中,多用于贴图、材质、动画、音频等资产:
[AssetReference的变量名].LoadAssetAsync<GameObject>();
直接实例化到场景中,一般用于Prefab:
[AssetReference的变量名].InstantiateAsync(pos, rot);
加载场景:
[AssetReference的变量名].LoadSceneAsync();
注:这几个API都是异步操作,异步操作详解在大智的教程中有(洪流学堂公众号中回复addr
可以获取),在这就不多说了。
2. 使用Addressables类中的静态方法通过地址/Label加载
Addressables类中有加载单个资源的API和多个资源的API。
加载单个资源
在脚本中使用字符串地址加载资产,先声明using UnityEngine.AddressableAssets;
名称空间,然后调用以下方法:
仅加载到内存中,多用于贴图、材质、动画、音频等资产:
Addressables.LoadAssetAsync<GameObject>("AssetAddress");
加载完成后并不会将所需的资产实例化到场景中。要将资产添加到场景中,还需要一步:实例化。
还有一个加载和实例化二合一的接口,这个接口会加载资产,然后立即将其实例化到场景中:
Addressables.InstantiateAsync("AssetAddress");
这会将指定地址的资产实例化到场景中。
注意:上面的API是异步操作。你可以在资产完成加载后提供一个回调来使用资产,异步操作详解在大智的教程中有(洪流学堂公众号中回复addr
可以获取),在这就不多说了。
using System.Collections;
using System.Collections.Generic;
using UnityEngine.AddressableAssets;
using UnityEngine;
public class AddressablesExample : MonoBehaviour {
GameObject myGameObject;
void Start{
Addressables.LoadAssetAsync<GameObject>("AssetAddress").Completed += OnLoadDone;
}
private void OnLoadDone(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<GameObject> obj)
{
// In a production environment, you should add exception handling to catch scenarios such as a null result.
myGameObject = obj.Result;
}
}
一次加载多个资产
一次加载多个资产通常是使用Label加载。
如上图所示的分组策略,可以按如下方式加载HD的皮肤贴图。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class TextureController : MonoBehaviour
{
public Renderer m_ReferencedMaterial;
public void SwitchToHighDef()
{
LoadTexture("ArcherColor", "HD");
}
void LoadTexture(string key, string label)
{
Addressables.LoadAssetsAsync<Texture2D>(new List<object> { key, label }, null, Addressables.MergeMode.Intersection).Completed
+= TextureLoaded;
}
void TextureLoaded(AsyncOperationHandle<IList<Texture2D>> obj)
{
m_ReferencedMaterial.material.mainTexture = obj.Result[0];
}
}
在这一定要注意:LoadAssetsAsync有三个重载:
public static AsyncOperationHandle<IList<TObject>> LoadAssetsAsync<TObject>(object key, Action<TObject> callback);
public static AsyncOperationHandle<IList<TObject>> LoadAssetsAsync<TObject>(IList<object> keys, Action<TObject> callback, MergeMode mode);
public static AsyncOperationHandle<IList<TObject>> LoadAssetsAsync<TObject>(IList<IResourceLocation> locations, Action<TObject> callback);
通常我们使用前两种重载:
第一种:用于加载单个标签或地址。
第二种:用于加载地址+标签的形式。用第二种时一定要注意加上第三个参数MergeMode。否则重载匹配时就会去匹配第一个重载,会导致找不到资源。
MergeMode是什么呢?翻译过来是合并模式。
public enum MergeMode
{
None = 0,
UseFirst = 0,
Union,
Intersection
}
采用第二种重载加载时,其实会去先查询每一个地址/标签对应的资源,然后再根据MergeMode进行最终结果的计算。
举个栗子:
比如传入的参数是new List<object>{"cube", "red"}
,根据cube查询出来的资源有A、B、D,根据red查询出来的资源有C、D、E。
那么MergeMode是Node或UseFirst时,会取第一个key查询到的资源:A、B、D;
MergeMode是Union时,会取所有key查询到的资源的并集:A、B、C、D、E;
MergeMode是Intersection时,会取所有key查询到的资源的交集:D。
总结
大智:“看来这个LoadAssetsAsync
就是你栽了的API吧?”
小新:“没错。”
大智:“之前我都有讲过哦,一定要注意这些细节。特别是方法有重载的时候,要注意查阅API文档或者阅读源码,不能想当然。”
《大话Unity2019》,大智带小新学Unity2019的有趣经历,让你学Unity更简单。