Addressables简单使⽤指南AddressablesManual 异步加载
资源地址就是在Addressables Groups⾥看到的具体资源的地址,只要给定地址就能到需要的资源
使⽤地址加载
// 参数为资源地址,包含后缀.prefab,handle.Result就是实例化的物体,⽽不是prefab
Addressables.InstantiateAsync("address of prefab");
// 参数为资源地址,包含资源后缀名
Addressables.LoadAssetAsync("address of asset");
使⽤直接资源引⽤AssetReference加载
AssetReference asset;
// 参数为资源地址,包含后缀.prefab
Addressables.InstantiateAsync(asset);
/
/ 参数为资源地址,包含资源后缀名
Addressables.LoadAssetAsync(asset);
异步回调
匿名委托
Addressables.InstantiateAsync($"address of prefab").Completed +=(handle)=>
{
if(handle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded)
{
var obj = handle.Result;
}
}
回调函数
Addressables.InstantiateAsync($"address of prefab").Completed += OnCompleted;
private void OnCompleted(AsyncOperationHandle<SceneInstance> handle)
{
if(handle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded)
{
var obj = handle.Result;
}
}
async
public static async void PlaySoundEffect(AssetReference audioClipAsset)
{
var handle = audioClipAsset.LoadAssetAsync<AudioClip>();
await handle.Task;
if(handle.Status == AsyncOperationStatus.Succeeded)
{
var audioClip = handle.Result;
}
}
async Task
private async static Task<T>LoadAssetAsync<T>()where T : Object
{
var path ="address of prefab";
var handle = Addressables.LoadAssetAsync<T>(path);
await handle.Task;
if(handle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded)
{
return handle.Result;
}
return null;
}
public static async Task<T>InstantiateAssetAsync<T>()where T : Object
{
var obj =await LoadAssetAsync<T>();
}
协程
public IEnumerator Start(){
AsyncOperationHandle<Texture2D> handle = Addressables.LoadAssetAsync<Texture2D>("mytexture");
yield return handle;
if(handle.Status == AsyncOperationStatus.Succeeded){
Texture2D texture = handle.Result;
// The texture is ready for use.
// ...
// Release the asset after its use:
Addressables.Release(handle);
}
}
同步加载
if can not find, go to Unity github repository and find the repository named addresables-sample
本地打包流程
在AddressableAssetsData/AssetGroups下到对应Group的配置,这⾥可以查看到Build Path的本地路径。
根据需要修改Advanced Options -> Bundle Mode
Pack Together:每个Group中,除了场景之外的资源,打成⼀个包,场景另外打⼀个包
Pack Separately:每个Group中的Entry分别打⼀个包,Entry即Group下的各个⽬录
Pack Together By Label:相同Label打⼀个包
⼿动打包:Addressables Group界⾯下,Build -> New Build -> Default Build Script
主菜单File -> Build Settings -> Build
AssetReference filter 过滤器
如果在Addressables Group界⾯⾥以⽂件夹为单位创建Entry,那么Inspector下的AssetReference打开的过滤器中会看到很多可选的筛选指定类型的asset
[Serializable]
public class AssetReferenceSceneAsset : AssetReferenceT<SceneAsset>
{
public AssetReferenceSceneAsset(string guid):base(guid){}
}
SceneAsset可换成其他资源类型,具体可通过在Project窗⼝右键Create,弹出的类型都是资源类型
筛选Component
ComponentReference.cs
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
#if UNITY_EDITOR
reference groupusing UnityEditor;
#endif
public class ComponentReference<TComponent>: AssetReference where TComponent : Component
{
public ComponentReference(string guid):base(guid)
{
}
public new AsyncOperationHandle<TComponent>InstantiateAsync(Vector3 position, Quaternion rotation, Transform parent =null)
{
return Addressables.ResourceManager.CreateChainOperation<TComponent, GameObject>(base.InstantiateAsync(position, Quaternion.identity, pare nt), GameObjectReady);
}
public new AsyncOperationHandle<TComponent>InstantiateAsync(Transform parent =null,bool instantiateInWorldSpace =false)
{
return Addressables.ResourceManager.CreateChainOperation<TComponent, GameObject>(base.InstantiateAsync(parent, instantiateInWorldSpace), GameObjectReady);
}
public AsyncOperationHandle<TComponent>LoadAssetAsync()
{
return Addressables.ResourceManager.CreateChainOperation<TComponent, GameObject>(base.LoadAssetAsync<GameObject>(), GameObjectRe ady);
}
AsyncOperationHandle<TComponent>GameObjectReady(AsyncOperationHandle<GameObject> arg)
{
var comp = arg.Result.GetComponent<TComponent>();
return Addressables.ResourceManager.CreateCompletedOperation<TComponent>(comp,string.Empty);
}
public override bool ValidateAsset(Object obj)
{
var go = obj as GameObject;
return go !=null&& go.GetComponent<TComponent>()!=null;
}
public override bool ValidateAsset(string path)
{
#if UNITY_EDITOR
//this load can
var go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
return go !=null&& go.GetComponent<TComponent>()!=null;
#else
return false;
#endif
}
public void ReleaseInstance(AsyncOperationHandle<TComponent> op)
{
// Release the instance
var component = op.Result as Component;
if(component !=null)
{
Addressables.ReleaseInstance(component.gameObject);
}
// Release the handle
// Release the handle
Addressables.Release(op);
}
}
[Serializable]
public class ComponentReferenceYourComponent : ComponentReference<YourComponent>
{
public ComponentReferenceYourComponent(string guid)
:base(guid){}
}
YourComponent为你的继承⾃Component的脚本组件
BUG
不到Sprite资源
Addressables.LoadAssetAsync("folder/sprite.png");
假设你的sprite在Addressables中的地址为folder/sprite.png
当使⽤版本⼤于1.3.8的Addressables时,在使⽤⾮Use Exsisting Build的模式时,⽆法到资源。
但当你的sprite的地址为sprite.png,不带任何⽗⽬录时,则不会出现以上问题。
正确的使⽤⽅法
使⽤版本1.3.8(或者更低版本,⽬前1.3.8 < 版本 <= 1.7.4的均存在该BUG)
Addressables.LoadAssetAsync("folder/sprite.png[sprite]");
/
/ 对于sprite atlas中只有⼀个sprite的情形,最后的[sprite]是可以省略的,以下代码也有效
Addressables.LoadAssetAsync("folder/sprite.png");
// 对于sprite atlas中有多个sprite的情形,最后的[sprite_0]不能省略,[sprite_0]为sprite atlas中的⽬标sprite名称
Addressables.LoadAssetAsync("folder/sprite.png[sprite_0]");
初始场景载⼊之前就使⽤异步加载,⼀直加载不完成
⽐如使⽤了标签[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]的游戏启动函数中,在游戏加载初始场景之前使⽤Addressables进⾏异步加载,则⼀直不会加载完成
解决⽅法就是在初始空场景中⽤⼀个Mono脚本的Start来作为游戏启动函数
让⽂件夹Addressable,⽂件夹名称和内部的资源名称有重复的部分,引发InvalidKeyException
string GetInternalIdFromFolderEntry(string keyStr, AddressableAssetEntry entry)
{
var entryPath = entry.AssetPath;
if(keyStr.StartsWith(entry.address +"/"))
return keyStr.Replace(entry.address, entryPath);
foreach(var l in entry.labels)
if(keyStr.StartsWith(l +"/"))
return keyStr.Replace(l, entryPath);
return string.Empty;
}
keyStr ="Config/DebugConfigData.asset";
entry.address ="Config";
entryPath ="Assets/AddressablesResources/Config";
Debug.Log(keyStr.Replace(entry.address, entryPath)=="Assets/AddressablesResources/Config/DebugAssets/AddressablesResources/ConfigData.asset") ;
⽂件夹名称为aaa,路径为"Assets/aaa"
资源名称为aaabbb.asset
勾选aaa⽂件夹的Addressable选项,那么资源的地址就是"aaa/aaabbb.asset"
仅当有⽂件夹时才会进⼊到这个函数,⽽Replace会将aaa替换为全路径,即"aaa" -> “Assets/aaa”,所以最终结果
是"Assets/aaa/Assets/aaabbb.asset"。绝了!你特么不会⽤IndexOf和SubString来分割字符串吗?
重命名资产的Address后,报错InvalidKeyException
Addressables 1.8.4版本
Project Settings -> Editor -> Enter Play Mode Options 勾选
Window -> Asset Management -> Addressables -> Groups -> Play Mode Script 选择 Use Asset Database
修改某个资源为错误的Address,在加载时会报错InvalidKeyException
将资源的Address修正,再次加载,仍会报错InvalidKeyException
将Project Settings -> Editor -> Enter Play Mode Options 不勾选(或者勾选Reload Domain),则加载正常
不执⾏上⼀步,⽽是改为重启Unity编辑器,也会加载正常
猜测是游戏启动后会先执⾏重建资源对应key的动作,再开始游戏。可能是某个静态构造函数内执⾏的,因为 Enter Play Mode Options 勾选 会导致静态类创建后即使下⼀次启动游戏也不会被销毁(静态类⽣命周期和Unity编辑器⼀致),静态构造函数就不会再次执⾏,但也可能是其他机制实现的
Addressables 1.16.10或更⾼版本
Project Settings -> Editor -> Enter Play Mode Options 勾选
Window -> Asset Management -> Addressables -> Groups -> Play Mode Script 选择 Use Asset Database
修改某个资源为错误的Address,在加载时会报错InvalidKeyException
将资源的Address修正,再次加载,仍会报错InvalidKeyException
将Project Settings -> Editor -> Enter Play Mode Options 不勾选(或者勾选Reload Domain),加载仍报错
懒得从源码原因了,如果遇到这个问题,注意把Addressables版本回退到1.8.4或者其他有效版本
参考
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论