一,两种资源加载方式对比

  1. 加载方式:

    • Resources 使用同步加载方式;Resources 加载资源时,应用程序将会被阻塞,直到资源加载完成,这可能会导致应用程序出现卡顿或挂起的情况。
    • Addressables 使用异步加载方式。这意味着使用 Unity 而使用 Addressables 加载资源时,应用程序可以继续运行,而不会出现卡顿或挂起的情况。
  2. 动态加载:

    • Resources 只能从项目的 Assets 文件夹中加载资源,只能在编译时加载资源。
    • Addressables 可以在运行时动态加载资源,从而实现更灵活的资源管理。
  3. 资源管理:

    • Resources 只能带在安装包中,资源过多的情况下,会增大包体。
    • Addressables 可以从本地或远程服务器加载资源,并可以通过 Addressables Group 进行灵活的资源管理和打包。
  4. 资源更新:

    • Resources 中的资源只能通过重新打包应用程序来更新
    • Addressables 可以通过简单的资源更新或替换来更新应用程序中的资源,而无需重新打包整个应用程序。

综上所述,Addressables 比 Resources 更灵活、更高效、更可靠,特别是在处理大量或较大的资源时,Addressables 的异步加载和灵活资源管理功能能够大大提高应用程序的性能和可扩展性。但是,在加载少量或较小的资源时,使用 Resources 会更简单和方便。


二,将Resource项目转为Addressables

2.1 实现逻辑

  • 当一个Resources文件夹内的资源被标记为Addressable时,系统会自动将它从Resources文件夹移动到Resources_moved的新文件夹中。
  • 若有多层目录,系统也会保留,同步在Resources_moved的新文件夹中创建和Resources中的目录结构
  • 被标记的资源可寻址路径(加载路径Key),也会使用Resources目录下的目录结构。
  • 原来的加载代码会从Resources.Load<GameObject>("CZY/Czhenya.prefab") 变成 Addressables.LoadAssetAsync<GameObject>("CZY/Czhenya.prefab")
  • 若工程中有使用public GameObject Czhenya; 这种公开变量拖拽赋值的情况,
    只需将定义代码修改为public AssetReference Czhenya;
    实例化Instaniate() 修改为 AssetRefName.InstantiateAsync();

需要注意的是: 移动后的路径Key使用在Resources文件夹下的目录命名。而在Resources文件夹下加载资源时路径名称是不区分大小写的,而AA的路径Key是需要区分大小写的。

分享一个工具脚本:

可导入下面脚本到工程中,而后只需将工程中的Resources.Load 修改 为 AAResources.Load 即可完成资源加载方式的转换。

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class AAResources
{
    /// <summary>
    /// 可寻址资源加载
    ///     强制同步加载GameObject的基本用法
    /// </summary>
    /// <param name="pathKey">路径key</param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T Load<T>(string pathKey)
    {
        var op = Addressables.LoadAssetAsync<T>(pathKey);
        T go = op.WaitForCompletion();
        if (op.Status == AsyncOperationStatus.Failed)
        {
            Debug.LogError($"加载资源失败,路径:{pathKey},异常 {op.OperationException}");
            return default(T);
        }
        return go;
    }
}

注意:这种同步加载的方式在WebGL上是不支持的,在其他平台是没问题的。
在这里插入图片描述

异步写法如下:

public async Task<T> LoadAssetAsync<T>(string pathKey) where T : UnityEngine.Object
{
    AsyncOperationHandle<T> handle = Addressables.LoadAssetAsync<T>(pathKey);
    await handle.Task;
    return handle.Result;
}

Addressable代码加载的其他方式,可以参考:Unity 之 Addressable可寻址系统 – 代码加载介绍 – 进阶(一)


2.2 操作步骤

将Unity资源加载方式从Resources修改到Addressables需要进行以下步骤:

  1. 安装 Addressables 包:在 Unity 的 Package Manager 中安装 Addressables 包,以便在项目中使用 Addressables 相关功能。

  2. 配置 Addressables:在 Unity 的菜单栏中选择 Window -> Asset Management -> Addressables -> Groups,创建一个新的 Addressables Group 并将所需的资源添加到其中。

  3. 修改代码:修改引用 Resources 加载方式的代码,改为使用 Addressables 加载资源。您可以使用 Addressables.LoadAssetAsync 方法来异步加载资源,或者使用 Addressables.LoadAsset 方法来同步加载资源。


三,使用Addressables的注意事项

在使用Addressables加载资源时,需要注意资源的生命周期和线程安全问题,下面是一些处理方法:

  • 生命周期管理:在使用Addressables加载资源后,需要注意资源的生命周期问题,以免资源泄漏或者被意外释放。一般来说,可以使用AsyncOperationHandle.Release()方法来释放加载的资源。在释放资源之前,需要确保所有的引用都已经被释放了,否则会导致资源泄漏。如果资源被多次加载,需要在所有的引用都释放之后,再调用Release()方法释放资源。

  • 线程安全:在使用Addressables加载资源时,需要注意线程安全问题,以免出现竞态条件和其他线程问题。一般来说,可以使用异步加载的方式来避免线程问题。如果需要在主线程中访问异步加载的结果,可以使用Unity的协程(Coroutine)来处理异步操作,并在协程中访问异步加载的结果。另外,需要注意在异步加载的回调函数中,不要直接修改Unity对象的属性或者调用Unity API,否则会导致线程问题。如果需要在回调函数中修改Unity对象的属性或者调用Unity API,需要使用Unity的主线程调用(MainThreadDispatcher)来确保线程安全。

  • 错误处理:在使用Addressables加载资源时,需要注意错误处理问题,以免出现未处理的异常和错误信息。一般来说,可以使用AsyncOperationHandle.OperationException属性获取异步操作的错误信息,并对错误进行处理。如果出现异常,可以使用try-catch语句来捕获并处理异常。需要注意的是,在异步操作中,异常和错误信息可能会被延迟到异步操作完成后才能被捕获和处理,所以需要在异步操作完成后再进行错误处理。


四,使用中遇到问题

报错:

UnityEngine.AddressableAssets.InvalidKeyException: Exception of type ‘UnityEngine.AddressableAssets.InvalidKeyException’ was thrown., Key=Sound, Type=UnityEngine.AudioClip

可能原因:

  1. 检查指定的组名称是否正确,需要保证与Addressable系统中的组名称一致,包括大小写。可以在Addressables窗口中查看所有的组名称和其中的资源。

  2. 检查指定的组中是否存在指定的资源,需要保证资源名称与Addressable系统中的名称一致,包括大小写。

  3. 检查指定的资源类型是否正确,需要保证与实际使用的资源类型一致。例如,如果需要加载的是音频资源,需要使用Addressables.LoadAssetsAsync而不是Addressables.LoadAssetsAsync。

  4. 如果使用了Addressables的标签(label)功能,需要保证指定的标签名称与实际使用的标签名称一致,包括大小写。


Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐