
Unity的Addressable资产系统支持同步加载,所以本文介绍下如何使用以及如何替换Resources.Load。
可寻址和同步加载
到现在只有异步加载方式
Addressable资产系统历来不支持同步加载,因此,需要通过如下所示的异步方法或协程等待加载完成。
// 异步方法
var handle = Addressables.LoadAssetAsync<GameObject>("FooPrefab");
await handle.Task; // 待机
var prefab = handle.Result;
// 协程
var handle = Addressables.LoadAssetAsync<GameObject>("FooPrefab");
yield return handle; // 待机
var prefab = handle.Result;
// 打回来
var handle = Addressables.LoadAssetAsync<GameObject>("FooPrefab").Completed += x =>
{
var prefab = handle.Result;
};
如果想同步获取资源,需要预加载或编写一个专用的Provider。
可以从这里参阅站内文章:Unity与Addressable资源系统同步加载资源
如何同步加载
传统的异步加载AsyncOperationHandle需要在waits或coroutines中等待,在同步加载的实现中,WaitForCompletion()可以通过调用同步等待。
using UnityEngine;
using UnityEngine.AddressableAssets;
public class Example : MonoBehaviour
{
private void Start()
{
// 像以前一样调用load方法
var op = Addressables.LoadAssetAsync<GameObject>("FooPrefab");
// 使用 WaitForCompletion 同步等待加载完成
var prefab = op.WaitForCompletion();
// 使用后释放(与之前相同)
Addressables.Release(op);
}
}
替换为Resources.Load
在那篇文章的实现方法中,由于需要释放资源,所以源码是多行的。
但是,考虑到替换已经写的Resources.Load内容,所以尽量写得简洁一点。
// 使用 Resources.Load 加载的示例
var prefab = Resources.Load<GameObject>("FooPrefab");
// 在Addressables中这样写(理想)
var prefab = Addressables.Load<GameObject>("FooPrefab");
用Addler写在一行
由于需要显式释放Addressables,因此上面的描述将跨越多行。因此,为了简明扼要地写出这个发布过程,使用了一个名为Addler的库。
可以从这里参阅:介绍Addressables生命周期Addler管理库
通过使用它,可以将资源生命周期与指定的GameObject关联起来,并在GameObject销毁时一起释放,如下图一行描述即可,不用担心忘记释放而导致内存泄露。
using Addler.Runtime.Core;
using UnityEngine;
using UnityEngine.AddressableAssets;
public class Example : MonoBehaviour
{
private void Start()
{
// 当游戏对象被销毁时,该资产会自动释放
var prefab = Addressables.LoadAssetAsync<GameObject>("FooPrefab").BindTo(gameObject).WaitForCompletion();
}
}
Addler的功能不仅限于此,它是一个包含对象池和预加载等功能的库。
这样简单的写
实际使用的时候,觉得把它包装起来,创建一个可以写得更简洁的类会更好。
using Addler.Runtime.Core;
using UnityEngine;
using UnityEngine.AddressableAssets;
public class ResourceLoader
{
private readonly GameObject _defaultBindTarget;
public ResourceLoader(GameObject defaultBindTarget)
{
_defaultBindTarget = defaultBindTarget;
}
public T Load<T>(string address, GameObject bindTarget = null)
{
if (bindTarget == null)
{
bindTarget = _defaultBindTarget;
}
return Addressables.LoadAssetAsync<T>(address).BindTo(bindTarget).WaitForCompletion();
}
}
如果这样做,可以非常简单地加载它,如下所示。
using Addler.Runtime.Core;
using UnityEngine;
using UnityEngine.AddressableAssets;
public class Example : MonoBehaviour
{
private ResourceLoader _resourceLoader;
private void Start()
{
_resourceLoader = new ResourceLoader(gameObject);
// 同步负载
_resourceLoader.Load<GameObject>("FooPrefab");
}
}
EZAddresser(自动分配类似资源的地址)
替换资源的另一个障碍是地址的设置,要加载上面的内容FooPrefab,需要提前设置地址FooPrefab为那个Prefab。

这是通过将资产拖放到上面的窗口中然后设置名称来完成的,但是手动执行此操作绝对不是人工工作。
使用EZAddresser,只需创建一个名为Addressables的文件夹并将资产放入其中,地址就会自动分配。
可以从这篇文章中了解:EZAddresser一个用于自动化可寻址地址设置工具
默认情况下,文件名将是地址,但如果更改设置,也可以使用Addressables文件夹的相对路径(无扩展名)作为地址,如Resources文件夹。
换句话说,如果使用此设置将现有Resources文件夹的名称更改为Addressables,则可以将Resources替换为Addressables。
但是请注意,此库需要Unity 2020或更高版本。
使用同步加载时的注意事项
手册描述了同步加载时需要注意的一些要点,从这里参阅。
等到所有AsyncOperations完成
考虑并行加载多个资产的情况,如只使用其中的一个WaitForCompletion()等待同步加载,可以直观的想象只有它会被同步等待,其他资源会被异步加载。然而实际上,WaitForCompletion()即使只完成其中一个,看起来也会同步等待,直到此时存在的所有AsyncOperations都完成。
这是一个相当微妙的规范,但它是对引擎的一个约束,只在可以很好地控制加载内容的情况下WaitForCompletion()使用。
加载影响性能
还写了Unity 2021.2.0之前的版本使用同步加载会影响性能,不知道它有多大影响,但WaitForCompletion()似乎调用时正在进行的负载处理越多,它的影响就越大。
请勿用于下载
如果资源不在本地,Addressable的加载方法将下载资源,这种行为WaitForCompletion()在使用时是一样的,但是像下载这样耗时的过程一般不应该被同步处理,因为它们会卡住。
所以WaitForCompletion()建议下载的时候不要使用(有意的话也可以)。
…
以上是关于Unity如何使用以及替换Resources.Load的全部内容,如果你有任何反馈,请随时在本页面下方留言。