前言
可寻址资产概述
可寻址资产系统包含两个包:
- 可寻址资产包(主包)
- 可编程构建管道包(依赖包)
当安装"可寻址资产包"时,会同时安装"可编程构建管道包"。请参阅最新版本的Unity Scriptable Build Pipeline文档。
概念
以下名词贯穿了整个文档:
- Address:资产的位置标识符,可轻松检索运行时。
- AddressableAssetData Directory:将可寻址资产元数据存储在项目Assets目录中。
- Asset group:一组可用于构建时处理的可寻址资产。
- Asset group schema:定义可分配给组并在构建期间使用的一组数据。
- AssetReference:对象的操作类似于直接引用,但具有延迟的初始化。该AssetReference对象将GUID存储为可按需加载的可寻址对象。
- Asynchronous loading:允许在开发过程中更改资产及其依赖项的位置,而无需更改游戏代码。异步加载是可寻址资产系统的基础。
- Build script:运行资产组处理器以打包资产,并为Resource资源管理器提供地址和位置之间的映射。
- Label:提供额外的可寻址资产标识符,以在运行时加载类似项(例如Addressables.DownloadDependenciesAsync("spaceHazards");)。
入门
一、安装可寻址资产包
可寻址资产系统需要Unity2018.3版本或更高版本。
安装:https://docs.unity3d.com/Packages/com.unity.package-manager-ui@1.7/manual/index.html
二、准备可寻址资产
1.标记资产为可寻址
在UnityEditor中,有两种方法可将资产标记为可寻址
- 在物件的Inspector面板中。
- 在Addressables Group窗口中。
- 使用Inspector窗口
在Project窗口中,选择所需的资产查看其Inspector面板。在Inspector面板中,点击Addressable复选框,然后输入用于标识资产的名称。
- 使用Addressables窗口
选择Window> AssetManager > Addressables > Groups 打开Addressables Groups窗口。接下来,将所需资产从Project窗口拖动到Addressables Groups窗口中的资产组之一。
2.指定资产地址
资产的默认地址是项目中资产的路径(例如Assets/images/myImage.png)。要从Addressables Groups窗口中更改资产的地址,右键单击资产然后选择Change Address。
首次使用可寻址资产时,系统会将项目的一些编辑时和运行时数据资产保存在Assets/AddressableAssetsData文件中,这些文件应添加到版本控制中。
3.构建可寻址内容
在构建应用程序之前,可寻址资产系统需要将你的内容构建到正在运行的游戏可以使用的文件中。此步骤不是自动的。您可以通过编辑器或API构建以下内容:
- 在编辑器中构建内容,打开Addressables Groups窗口,然后选择Build > New Build > Default Build Script。
- 使用API构建内容,可以使用AddressableAssetSettings.BuildPlayerContent()。
包资产
将package资产标记为可寻址需要Unity2020.2.0a9或更高版本。
标记package资产为可寻址
当前,package中的资产无法在Inspector面板中标记为“可寻址”。你只能使用Addressables Groups窗口将其标记为“可寻址”。
在包中创建Addressable Groups
在Addressable Groups窗口中创建一个组。完成修改后保存。将该组资产及其它的schema资产移动到包中。
打开一个使用以上包的新项目。如果您的组具有“内容打包和卸载”schema,请更新其构建和加载路径。现在,您的组可以包含在您的下一个“可寻址对象”构建中。
如果要再次修改组,确保关闭所有使用该包的项目,并在保存所有修改后重新打开它们。这将重新加载组资产。如果组具有“内容打包和卸载”schema,请再次更新其构建和加载路径。
三、使用可寻址资产
1.通过地址加载或实例化
你可以在运行时加载或实例化可寻址资产。加载资产会将所有依赖项加载到内存中(包括AssetBundle数据(如果适用)),使你可以在需要时使用资产。这实际上并没有将所需的资产放到场景中。要将资产添加到场景中,必须实例化。使用可寻址实例化接口将加载资产,然后立即将其添加到场景中。
要从游戏脚本中使用字符串地址访问资产,需要声明UnityEngine.AddressableAssets名称空间
using UnityEngine.AddressableAssets;
然后调用以下方法:
- 使用指定的地址加载资产。
Addressables.LoadAssetAsync<GameObject>("AssetAddress");
- 将具有指定地址的资产实例化到场景中。
Addressables.InstantiateAsync("AssetAddress");
注意:LoadAssetAsync和InstantiateAsync是异步操作。您可以提供一个回调,以在资产完成加载后使用该资产(Async operation handling更多操作:https://docs.unity3d.com/Packages/com.unity.addressables@1.14/manual/AddressableAssetsAsyncOperationHandle)。
using System.Collections;
using System.Collections.Generic;
using UnityEngine.AddressableAssets;
using UnityEngine;
public class AddressablesExample : MonoBehaviour {
GameObject myGameObject;
...
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;
}
}
子资产和组件
子资产和组件是资产加载的特殊情况。
- 组件
您不能直接通过可寻址对象加载一个GameObject的组件。您必须加载或实例化GameObject,然后从中获得组件引用。
怎么扩展可寻址来支持组件加载,参阅:https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/ComponentReference
- 子资产
可寻址资产系统支持加载子资产,但是需要特殊的语法。潜在子资产的示例包括Sprite sheet中的Sprites 或 在FBX文件中的animation clips。有关直接加载精灵的示例,请参见我们的精灵加载示例:https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/Sprite%20Land
要加载资产中的所有子对象,可以使用以下示例语法:
Addressables.LoadAssetAsync<IList<Sprite>>("MySpriteSheetAddress");
要在资产中加载单个子对象,可以执行以下操作:
Addressables.LoadAssetAsync<Sprite>("MySpriteSheetAddress[MySpriteName]");
资产中可用的名称在main Addressables group editor window中可见。此外,您可以使用AssetReference来访问资产的子对象。请参阅以下部分中的注释。
????
SpriteAtlas特别是对于对象,请确保在对象上启用了“ 包含在内部 ” SpriteAtlas。如果禁用了“ 包含在构建中”,则SpriteAtlas不能以任何形式构建,包括由Addressables完成的内容构建。
使用AssetReference类
AssetReference类提供一种方法来访问寻址的资产,而无需知道他们的地址。要使用AssetReference该类访问可寻址资产:
- 从场景Hierarchy面板或Project窗口选择一个GameObject 。
- 在Inspector中,点击Add Component按钮,然后选择组件类型。任何可序列化的组件都可以支持AssetReference变量(例如,游戏脚本,ScriptableObject或其他可序列化的类)。
- 在组建中添加一个公有的AssetReference变量(例如public AssetReference explosion;)。
- 在Inspector面板中,通过将资产从Project窗口中拖动到显示的AssetReference字段中,或从项目中先前定义的可寻址资产的下拉列表中进行选择,来选择要链接到对象的可寻址资产(如下所示)。
要加载或实例化AssetReference资产,请调用其相应的方法。例如:
AssetRefMember.LoadAssetAsync<GameObject>();
或者
AssetRefMember.InstantiateAsync(pos, rot);
注:与正常寻址的资产,LoadAssetAsync并且InstantiateAsync是异步操作。您可以提供一个回调,以在资产完成加载后使用该资产(有关更多信息,请参见有关异步操作处理的文档:https://docs.unity3d.com/Packages/com.unity.addressables@1.14/manual/AddressableAssetsAsyncOperationHandle)。
子资产
如果将包含子资产的资产(例如SpriteAtlas或FBX)添加到AssetReference,则可以选择引用该资产本身或子资产。您惯常看到的单个下拉列表变为两个。第一个选择资产本身,第二个选择子资产。如果您选择“在第二个下拉菜单中,将被视为对主资产的引用。
四、构建注意事项
1.StreamingAssets中的本地数据
可寻址资产系统在运行时需要一些文件才能知道要加载什么以及如何加载它。这些文件是在构建Addressables数据并在StreamingAssets文件夹中结束时生成的,该文件夹是Unity中的一个特殊文件夹,其中包含其所有文件。生成可寻址内容时,系统会在库中暂存这些文件。然后,在构建应用程序时,系统将所需的文件复制到StreamingAssets,构建然后从文件夹中删除它们。这样,您可以构建多个平台的数据,而每个构建中仅包含相关数据。
除了特定于可寻址对象的数据外,任何构建其数据供本地使用的组也将使用特定于库平台的暂存位置。
要验证此方法是否有效,请将构建路径和加载路径设置为分别以[UnityEngine.AddressableAssets.Addressables.BuildPath]和开头的配置文件变量。
您可以在AddressableAssetSettings的Inspector面板中指定这些设置(默认情况下,此对象位于项目的目录中:Assets/AddressableAssetsData)。
2.提前下载
调用该Addressables.DownloadDependenciesAsync()方法将为您传入的地址或标签加载依赖项。通常是AssetBundle。
通过调用以上方法返回的AsyncOperationHandle结构体包含了一个PercentComplete属性,这个属性可用于监视和显示下载进度。您还可以让应用程序等待内容加载完毕。
关于PercentComplete
PercentComplete考虑到一些底层操作处理方面通过单个AsyncOperationHandle。在某些情况下,进度不是线性的,或者有些线性的。这可能是因为快速操作的权重与操作所需的时间相同。
例如,给定您希望从远程位置加载的资产,该资源的下载时间很短,并且依赖于本地捆绑包,因此PercentComplete在继续之前,您会看到跳到50%。这是因为本地捆绑包的加载速度比远程捆绑包快得多。但是,系统仅知道完成需要两个操作。
如果您希望在下载之前征求用户的同意,请使用Addressables.GetDownloadSize()来返回需要多少空间才能从给定的地址或标签下载内容。请注意,这考虑了仍在Unity资产捆绑缓存中的所有先前下载的捆绑。
事先为您的应用下载资产可能会很有利,但在某些情况下,您可能会选择不下载。例如:
- 如果您的应用程序包含大量在线内容,并且您通常希望用户仅与应用程序的一部分进行交互。
- 您有一个必须在线连接才能运行的应用程序。如果您所有应用程序的内容都捆绑在一起,则可以根据需要选择下载内容。
您可以使用预加载功能来显示下载已开始,然后继续进行操作,而不是使用完成百分比来等待内容加载。此实现需要一个加载或等待屏幕来处理资产到需要时尚未完成加载的情况。
3.多平台构建
在构建应用程序内容时,可寻址资产系统会生成包含您的可寻址资产的AssetBundles。AssetBundles依赖于平台,因此必须为要支持的每个唯一平台重新构建。
默认情况下,构建Addressables app数据时,给定平台的数据存储在Addressables构建路径的特定于平台的子目录中。运行时路径说明了这些平台文件夹,并指向适用的app数据。
注意:如果在编辑器播放模式下使用Addressables BuildScriptPackedPlayMode脚本,则Addressables将尝试为当前活动的构建目标加载数据。这样,如果您当前的构建目标数据与当前的Editor平台不兼容,则可能会出现问题。有关更多信息,请参阅播放模式脚本文档。
注意:如果一个组具有“内容打包和卸载”sechma,则可以在Inspector窗口中修改其压缩模式。为了获得最佳的资产加载时间,无论使用哪种平台,请仅对本地内容使用LZ4,对在线内容使用LZMA。
4.分组资产
逻辑上将资产分为多个组而不是将它们全部放在一个大的组中是一个好习惯。此方法的主要好处是:当多个贡献者对同一个文件进行编辑时,避免版本控制系统(VCS)中发生冲突。拥有一个大型资产组可能会导致VCS无法干净地合并这些各种更改。
5.构建打包在一起的场景
在一个有多个场景的可寻址资产组进行构建后,如果满足以下条件,这些场景将相互依赖:
- Packed Assets下在Project窗口中,该组的Bundle Mode设置为Pack Together。
- 该组中的场景均具有相同的资产标签,并且Bundle Mode设置为Pack Together By Label。
如果您甚至修改了这些分组场景中的一个,然后执行content update build,则所有相互依赖的场景将一起移动到新的内容更新组中。
6.加载内容目录
内容目录是可寻址对象用于根据提供给系统的密钥查找资产的物理位置的数据存储。默认情况下,可寻址对象为本地可寻址组构建本地内容目录。如果在AddressableAssetSettings下打开Build Remote Catalogs选项,则将建立一个附加目录来存储远程可寻址组的位置。最终,可寻址对象仅使用这些目录之一。如果构建了远程目录,并且其哈希与本地目录不同,则将下载,缓存和使用它来代替内置本地目录。
但是,可以指定其他要加载的内容目录。您可能有不同的原因,可能会决定为项目添加合适的目录,例如构建要在不同项目中使用的纯艺术品项目。
如果您发现加载其他目录很适合您,则有一种方法可以在这方面提供帮助LoadContentCatalogAsync。
对于LoadContentCatalogAsync,仅需要您提供要加载的目录的位置。但是,仅此一项并不使用目录缓存,因此,如果要从远程位置加载目录,请当心。每次需要加载该目录时,都会引发该WebRequest。
为了帮助您避免每次都需要下载远程目录,如果.hash您在加载的目录旁边提供了带有目录哈希值的文件,我们可以使用它来适当地缓存您的内容目录。
请注意:hash文件确实需要位于相同的位置,并具有与目录相同的名称。路径的唯一区别应该是扩展名。
还有一点要注意:您会注意到该方法带有一个参数autoReleaseHandle。为了使系统下载新的远程目录,LoadContentCatalogAsync需要释放对该点的所有先前调用,以指向您尝试加载的目录。否则,系统将从我们的操作缓存中选择“内容目录”加载操作。如果选择了缓存的操作,则不会下载新的远程目录。如果设置为true,则该参数autoReleaseHandle可以确保操作完成后不会停留在操作缓存中。