使用 Adressables 组织管理 Asset
Addressables 包基于 Unity 的 AssetBundles 系统,并提供了一个用户界面来管理您的 AssetBundles。当您使一个资源可寻址(Addressable)时,您可以使用该资源的地址从任何地方加载它。无论资源是在本地应用程序中可用还是存储在远程内容分发网络上,Addressable 系统都会定位并返回该资源。
您可以使用此包远程分发内容、在运行时管理内容加载、控制应用程序资源的托管位置以及管理资源之间的依赖关系。
Addressable Asset System 允许开发者通过资源的地址来请求资源。资源(例如预制件)标记为“Addressable”后,就会生成一个可从任何地方调用的地址。无论资源位于何处(本地还是远程),系统都会找到资源及其依赖项,然后将其返回。
Addressables 使用异步加载来支持从具有任何依赖关系集合的任何位置进行加载。无论开发者一直以来使用的是直接引用、传统资源包还是 Resource 文件夹,Addressables 都提供了一种使游戏更具动态性的简单方法。Addressables 使用了资源包,并会管理所有复杂性。
Addressables 概述
Addressables 提供了一个可以随项目扩展的系统。您可以从一个简单的设置开始,然后随着项目复杂性的增加进行重组,并且只需最少的代码更改。
例如,您可以从一组 Addressable 资源开始,Unity 会将其作为一个集合加载。然后,随着您添加更多内容,可以将资源拆分为多个组,以便在特定时间仅加载所需的资源。随着团队规模的增长,您可以创建单独的 Unity 项目来开发不同类型的资源。这些辅助项目(auxiliary projects)可以生成自己的 Addressables 内容构建,并从主项目(main project)中加载。
Addressables 系统提供了自动依赖关系和内存管理、有效的 AssetBundle 打包以及远程或本地托管资源的能力。使用这个包可以控制应用程序如何管理、加载和卸载资源。
默认情况下,Addressables 使用 AssetBundles 打包资源。您还可以实现自己的 IResourceProvider 类以支持其他访问资源的方式。
资源地址(Asset addresses)
Addressables 系统的一个关键特性是您可以为资源分配地址,并在运行时使用这些地址加载资源。Addressables 资源管理器在内容目录(content catalog)中查找地址,以确定资源的存储位置。资源可以内置到您的应用程序中、本地缓存或远程托管。资源管理器(resource manager)加载资源及其所有依赖项,如果需要,会先下载内容。
由于地址不与资源的物理位置绑定,因此您可以在 Unity 编辑器和运行时管理和优化资源。目录将地址映射到物理位置。
虽然最好为资源分配唯一的地址,但资源地址不一定必须唯一。在有用时,您可以将相同的地址字符串分配给多个资源。例如,如果您有资源的不同变体,可以将相同的地址分配给所有变体,并使用标签区分变体:
Asset 1: address: "plate_armor_rusty", label: "hd"
Asset 2: address: "plate_armor_rusty", label: "sd"
对于 Addressables API 中仅加载单个资源的方法(例如 LoadAssetAsync
),如果您使用分配给多个资源的地址调用它们,则会加载通过该地址找到的第一个实例。其他方法,如 LoadAssetsAsync
,一次加载多个资源,并加载具有指定地址的所有资源。
可以使用
LoadAssetsAsync
的MergeMode
参数来加载两个键的交集。
在前面的示例中,您可以指定地址 “plate_armor_rusty” 和标签 “hd” 作为键,并将交集作为合并模式来加载资源1。然后可以将标签值更改为 “sd” 以加载资源2。
有关如何为资源分配地址的更多信息,请参阅使资源可寻址。有关如何通过键(包括地址)加载资源的信息,请参阅加载资源。
AssetReference
AssetReference
是一种可以设置为任何类型 Addressable 资源的类型。Unity 不会自动加载分配给引用(AssetReference)的资源,因此您可以更好地控制何时加载和卸载它。
在 MonoBehaviour
或 ScriptableObject
中使用 AssetReference
类型的字段,以指定用于该字段的 Addressable 资源(而不是使用指定地址的字符串)。AssetReference
支持拖放和对象选择器分配,使其在编辑器检查器中更方便使用。
Addressables 还提供了一些更专门的类型,如 AssetReferenceGameObject
和 AssetReferenceTexture
。您可以使用这些专门的子类来防止将错误的资源类型分配给 AssetReference
字段。您还可以使用 AssetReferenceUILabelRestriction
属性将分配限制为具有特定标签的资源。
请参阅使用 AssetReferences以获取更多信息。
资源加载和卸载(Asset loading and unloading)
要加载一个 Addressable 资源,您可以使用它的地址或其他键(如标签或 AssetReference
)。请参阅加载 Addressable 资源以获取更多信息。您只需加载主资源(main asset),Addressables 会自动加载任何依赖资源。
当您的应用程序在运行时不再需要访问某个 Addressable 资源时,必须释放它,以便 Addressables 可以释放相关的内存。Addressables 系统保持对已加载资源的引用计数,直到引用计数返回到零才会卸载资源。因此,您无需跟踪资源或其依赖项是否仍在使用中。只需确保每次显式加载资源时,在应用程序不再需要该实例时释放它。请参阅释放 Addressable 资源以获取更多信息。
依赖关系和资源管理(Dependency and resource management)
Unity 中的一个资源可以依赖于另一个资源。例如,一个场景可能引用一个或多个预制件,或一个预制件可能使用一个或多个材质。一个或多个预制件可以使用相同的材质,这些预制件可以存在于不同的 AssetBundles 中。当您加载一个 Addressable 资源时,系统会自动找到并加载它引用的任何依赖资源。当系统卸载一个资源时,它也会卸载其依赖项,除非有其他资源仍在使用它们。
随着您加载和释放资源,Addressables 系统为每个 item 保持引用计数。当一个资源不再被引用时,Addressables 会卸载它。如果该资源在一个不再有任何正在使用的资源的 Bundle 中,Addressables 也会卸载该 Bundle。
请参阅内存管理以获取更多信息。
Addressables 组(Group)和标签(Label)
使用 Addressables 组来组织内容。所有 Addressable 资源都属于某一个组。如果您未明确将资源分配给组,Addressables 会将其添加到默认组。
您可以设置组设置,以指定 Addressables build system 如何将组中的资源打包到 Bundle 中。例如,您可以选择将组中的所有资源打包在一个 AssetBundle 文件中。
使用标签标记您希望以某种方式一起处理的内容。例如,如果您定义了红色、帽子和羽毛的标签,可以在一个操作中加载所有带羽毛的红色帽子,无论它们是否属于同一个 AssetBundle。您还可以使用标签决定如何将组中的资源打包到 Bundle 中。
使用 Addressables 组窗口将资源添加到组中,并在组之间移动资源。您还可以在组窗口中为资源分配标签。
组纲要(Group Schema)
分配给组的 Schema 定义了用于构建组中资源的设置。不同的 schema 可以定义不同的设置组。例如,一个标准 schema 定义了如何将资源打包和压缩到 AssetBundles 中的设置(以及其他选项)。另一个标准 schema 定义了组中的资源属于的类别(可以在发布后更改和不能在发布后更改)。
您可以定义自己的 schema 以使用自定义构建脚本。
有关组架构的更多信息,请参阅 Schema 。
内容目录(Content Catalogs)
Addressables system 生成一个内容目录文件,将资源的地址映射到其物理位置。它还可以创建一个包含目录的哈希的哈希文件。如果您远程托管 Addressable 资源,系统会使用此哈希文件决定内容目录是否已更改以及是否需要下载它。请参阅内容目录以获取更多信息。
在执行内容构建时选择的配置文件决定了内容目录中的地址如何映射到资源加载路径。有关更多信息,请参阅配置文件。
有关远程托管内容的信息,请参阅远程分发内容。
内容构建(Content Builds)
Addressables 系统将 Addressable content 的构建与 player 的构建分开。内容构建生成内容目录、目录哈希和包含资源的 AssetBundles。
由于资源格式是特定于平台的,因此在构建 player 之前,必须为每个平台进行内容构建。
请参阅构建 Addressable 内容以获取更多信息。
Player 模式脚本(Play Mode Scripts)
当您在 play 模式下运行游戏或应用程序时,每次按下 Player 按钮之前都执行内容构建会很麻烦且缓慢。同时,您希望能够在尽可能接近 build player 的状态下运行游戏。Addressables 提供了三个选项,决定 Addressables 系统如何在 Player 模式下定位和加载资源:
- 使用资源数据库(Asset Database):Addressables 直接从资源数据库加载资源。如果您同时进行代码和资源更改,此选项通常提供最快的迭代速度,但最不像生产构建(production build)。
- 使用现有构建:Addressables 从您最后的内容构建中加载内容。此选项最像生产构建,如果您不更改资源,则提供快速的迭代周转。
- 模拟(无构建):此选项在不执行实际构建的情况下模拟内容构建,适合快速测试。
有关更多信息,请参阅play 模式脚本。
Addressables 工具
Addressables 系统提供以下工具和窗口,帮助您管理 Addressable 资源:
- Addressable Groups window:用于管理资源、组设置和构建的主界面。
- 配置文件窗口(Profiles window):帮助设置构建使用的路径。
- 构建布局报告(Build layout report):描述内容构建生成的 AssetBundles。
安装 Addressables
要在项目中安装 Addressables 包,请使用 Package Manager(包管理器):
- 打开 Package Manager(菜单:
Window > Package Manager
)。 - 将包列表设置为显示来自 Unity Registry 的包。
- 在列表中选择 Addressables 包。
- 点击安装(在 Package Manager 窗口的右下角)。
安装后要在项目中设置 Addressables 系统,请打开Windows/Addressables/Groups
窗口并点击 Create Addressables Settings
。
初始化 Addressables 系统前的 Addressables Groups 窗口当你选择 Create Addressables Settings 时,Addressables 系统会创建一个名为 AddressableAssetsData
的文件夹,用于存储设置文件和其他资源,这些文件是包用来跟踪 Addressables 配置的。将此文件夹中的文件添加到你的版本控制系统中。随着你更改 Addressables 配置,Addressables 包可能会创建其他文件。更多信息,请参阅 Addressables Settings 。
配置项目以使用 Addressables
安装包后,你需要为资源分配地址并重构任何运行时加载代码。
虽然你可以在项目开发的任何阶段集成 Addressables,但最佳实践是在新项目中立即开始使用 Addressables,以避免在开发后期进行不必要的代码重构和内容规划更改。
转换为 Addressables
使用 Addressables 构建的内容仅引用在该 Addressables build 中 build 的其他资源。通过场景数据(Scene data)和资源文件夹(Resource folders)包含在 Addressables 和 Player 构建中的内容在磁盘和内存中都会被重复加载。因此,你必须将所有场景数据和资源文件夹转换为 Addressables 构建系统。这将减少因重复而产生的内存开销,并意味着你可以使用 Addressables 管理所有内容。这也意味着内容可以是本地的或远程的,你可以通过内容更新(content update)构建来更新它。
要将项目转换为 Addressables,你需要根据当前项目引用和加载资源的方式执行不同的步骤:
- Prefabs(预制件):有关如何将预制件数据升级到 Addressables ,请参阅 Convert prefabs 。
- AssetBundles(资源包):有关如何将 AssetBundles 升级到 Addressables,请参阅 Convert AssetBundles 。
- StreamingAssets(流媒体资源):Unity 会将 StreamingAssets 文件夹中的任何文件按原样包含在构建的 Player应用程序中。
StreamingAssets 文件夹中的文件
当你使用 Addressables 系统时,可以继续从 StreamingAssets 文件夹加载文件。然而,这个文件夹中的文件不能是 Addressable,也不能引用项目中的其他资源。
Addressables 系统在构建期间将其运行时配置文件和本地 AssetBundles 放置在 StreamingAssets 文件夹中。Addressables 在构建过程结束时会删除这些文件,你不会在 Unity Editor 中看到它们。
转换场景数据
要将场景数据转换为 Addressable,需要将场景从构建设置列表中移出并将这些场景设为 Addressable。构建设置列表中必须有一个场景,这是 Unity 在应用程序启动时加载的场景。你可以创建一个新场景,该场景仅用于加载第一个 Addressable 场景。
转换场景的步骤:
- 创建一个新的初始化场景。
- 打开 Build Settings 窗口(菜单:
File > Build Settings
)。 - 将初始化场景添加到场景列表中。
- 从列表中移除其他场景。
- 在项目列表中选择每个场景,并在其 Inspector 窗口中启用 Addressable 选项。或者,你可以将场景资源拖到 Addressables Groups 窗口中的某个组中。不要将新的初始化场景设为 Addressable。
- 更新用于加载场景的代码,使用 Addressables 类的场景加载方法,而不是 SceneManager 方法。
你现在可以将一个大的 Addressable 场景组拆分为多个组。最佳方式取决于项目目标。你可以将场景移到它们自己的组中,以便可以独立加载和卸载每个场景。通过使资源本身成为 Addressable,可以避免复制被两个不同 AssetBundle 引用的同一资源。通常,最好将共享资源移动到它们自己的组中,以减少 AssetBundles 之间的依赖性。
在非 Addressable 场景中使用 Addressable 资源
对于你不想设为 Addressable 的场景,仍然可以通过 AssetReferences
将 Addressable 资源作为场景数据的一部分使用。
当你将一个 AssetReference 字段添加到自定义 MonoBehaviour 或 ScriptableObject 类中时,可以在 Unity 编辑器中将一个 Addressable 资源分配给该字段,方式类似于直接引用资源。主要区别在于,你需要为类添加代码以加载和释放分配给 AssetReference 字段的资源(而 Unity 在实例化场景中的对象时会自动加载直接引用)。
将直接引用替换为 AssetReferences
要在自定义类中用 AssetReferences 替换直接引用,请执行以下步骤:
- 用 AssetReferences 替换对象的直接引用(例如,将
public GameObject directRefMember;
替换为public AssetReference assetRefMember;
)。 - 将资源拖到组件的 Inspector 中,方式类似于直接引用。
- 添加运行时代码,使用 Addressables API 加载分配的资源。
- 添加代码,在不再需要时释放加载的资源。
转换 Prefab
要将预制件(prefab)转换为 Addressable 资源,请在其 Inspector 窗口中启用 Addressables 选项,或将其拖到 Addressables Groups 窗口中的某个组中。
在 Addressable 场景中使用预制件时,不总是需要将预制件设为 Addressable。Addressables 会自动将你添加到场景层次结构中的预制件包含在场景的 AssetBundle 数据中。如果在多个场景中使用同一个预制件,请将该预制件设为 Addressable 资源,以避免在每个使用它的场景中重复预制件数据。如果你希望在运行时动态加载和实例化预制件,也必须将其设为 Addressable。
转换 Resources 文件夹
如果你的项目在 Resources 文件夹中加载资源,可以将这些资源迁移到 Addressables 系统:
- 将资源设为 Addressable:要实现这一点,可以在每个资源的 Inspector 窗口中启用 Addressable 选项,或者将资源拖到 Addressables Groups 窗口中的某个组。
- 更改运行时代码:将使用 Resources API 加载资源的任何代码更改为使用 Addressables API 加载资源。
- 添加代码释放资源:在不再需要时释放加载的资源。
如果将以前在 Resources 文件夹中的所有资源保存在一个组中,可以期望获得类似的加载和内存性能。
当你将 Resources 文件夹中的资源标记为 Addressable 时,Unity 会自动将资源移动到项目中名为 Resources_moved 的新文件夹中。移动后的资源的默认地址是旧路径,不包含文件夹名称。例如,你的加载代码可能会从:
Resources.LoadAsync<GameObject>("desert/tank.prefab");
更改为:
Addressables.LoadAssetAsync<GameObject>("desert/tank.prefab");
在将项目更改为使用 Addressables 系统后,可能需要以不同方式实现 Resources 类的某些功能。
例如,如果运行如下命令 Resources.LoadAll<SampleType>("MyPrefabs");
从 Resources/MyPrefabs/ 文件夹加载资源,Unity 会加载 Resources/MyPrefabs/ 中所有与 SampleType 类型匹配的资源。
由于 Addressables 系统不支持这种确切的功能,需要更改工作流程以适应 Addressables 系统。在这种情况下,可以使用Addressable labels
实现类似的效果。
转换 AssetBundles
当你第一次打开 Addressables Groups 窗口时,Unity 会提供将所有 AssetBundles 转换为 Addressables Group
的选项。这是将 AssetBundle 设置迁移到 Addressables 系统的最简单方法。不过,你仍然需要更新运行时代码,以使用 Addressables API 加载和释放资源。
如果你想手动转换 AssetBundle 设置,请点击 Ignore 按钮。手动将 AssetBundles 迁移到 Addressables 的过程与场景和 Resources 文件夹的转换类似:
- 将资源设为 Addressable:通过在每个资源的 Inspector 窗口中启用 Addressable 属性,或者将资源拖到 Addressables Groups 窗口中的某个组,来将资源设为 Addressable。Addressables 系统会忽略现有的 AssetBundle 和标签设置。
- 更改运行时代码:将使用 AssetBundle 或 UnityWebRequestAssetBundle API 加载资源的任何代码更改为使用 Addressables API 加载资源。你不需要显式加载 AssetBundle 对象或资源的依赖项;Addressables 系统会自动处理这些方面。
- 添加代码释放资源:在不再需要时释放加载的资源。
如果你选择了自动转换选项或手动将资源添加到相应的 Addressables 组中,那么根据你的组设置,最终会得到包含相同资源的一组 bundle 。不过,bundle 文件本身可能不会完全相同。
使 Asset 成为 Addressable
你可以通过以下方式之一使资源成为 Addressable:
- 在资源的 Inspector 窗口中启用 Addressable 属性。
- 在 Inspector 窗口中将资源分配给 AssetReference 字段。
- 将资源拖到 Addressables Groups 窗口中的某个组。
- 在 Project 窗口中将资源移动到标记为 Addressable 的文件夹中。
一旦你将资源设为 Addressable,除非你将它放在特定的组中,Addressables 系统会将它添加到默认组中。当你构建内容时,Addressables 会根据你的组设置将组中的资源打包到 AssetBundles 中。你可以使用 Addressables API 加载这些资源。
Addressables 示例
Addressables 包含一些示例,你可以下载到项目中。要访问这些示例,请转到 Window > Package Manager > Addressables
。
这些示例包括如何在构建过程中禁用资源导入、创建自定义构建和 Play 模式脚本,以及提供 AddressableUtility 类的示例。
下载并导入示例后,它们会被放置在项目中的 Assets/Samples/Addressables/{AddressablesVersionNumber}
路径下。
示例 | 描述 |
---|---|
Addressables Utility | 包含一组 Addressables 的实用函数。脚本包含一个静态方法 GetAddressFromAssetReference ,该方法提供用于内部引用给定AssetReference 的 Addressable 地址。 |
ComponentReference | 创建一个受限于包含特定组件的 AssetReference 。有关详细信息,请参阅位于 Addressables Samples 仓库中的 ComponentReference 示例项目。 |
Custom Build and Playmode Scripts | 包含两个 custom scripts :* 示例中的 Editor/CustomPlayModeScript.cs 中的自定义 Play 模式脚本。此脚本的工作方式类似于已经包含的“Use Existing Build(需要 built groups )” Play 模式脚本。添加的方法是 CreateCurrentSceneOnlyBuildSetup 和 RevertCurrentSceneSetup ,位于 CustomBuildScript 中。示例中的 Editor/CustomBuildScript.cs 中的自定义构建脚本。此自定义构建脚本创建一个仅包含当前打开场景的构建。自动创建引导场景,并添加一个脚本,在启动时加载构建的场景。对于这些示例,默认使用的构建和加载路径分别是 [UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget] 和 {UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget] 。此类的 ScriptableObject 已经创建,但你可以使用Create 菜单再创建一个 ScriptableObject 。对于这个CustomPlayModeScript ,创建菜单路径是Addressables > Content Builders > Use CustomPlayMode Script 。默认情况下,这会创建一个 CustomPlayMode.asset ScriptableObject。CustomBuildScript 也遵循相同的步骤。 |
Disable Asset Import on Build(Deprecated) | 提供一个脚本,在玩家构建期间禁用资源导入。这样可以提高构建性能,因为在构建时,AssetBundles 会被复制到 StreamingAssets 。此示例仅适用于 2021.2 之前的编辑器版本。在 2021.2+ 版本中,编辑器提供了将 Assets/ 之外的文件夹包含到 StreamingAssets 中的能力。导入示例到项目后,可以通过新的菜单项 Build/Disabled Importer Build 触发不导入资源的玩家构建。构建输出默认放置在 DisabledImporterBuildPath/{EditorUserBuildSettings.activeBuildTarget}/ 中。可以编辑示例类 DisableAssetImportOnBuild 来修改构建路径。 |
Import Existing Group | 包含一个工具,可以将组资源(例如自定义 package 中的资源)导入到当前项目中。该工具位于 Window/Asset Management/Addressables/Import Groups 下。窗口需要 AddressableAssetGroup.asset scriptable object 的路径、组名以及与导入的 AddressableAssetGroup 相关的任何 schemas 文件夹。 |
Prefab Spawner | 提供一个基本脚本,用于实例化和销毁预制件 AssetReference 。要使用此示例,将提供的脚本 PrefabSpawnerSample 附加到场景中的某个 GameObject 上。将一个 Addressable 资源分配给该脚本的 AssetReference 字段。如果使用“使用现有构建(Use Existing Build )” Play 模式脚本,确保已构建 Addressable 内容。然后进入 Play 模式。 |
参考
- com.unity.addressables
- Addressables-Sample
- addressables-planning-and-best-practices
- Why use Addressables? - Unity Learn course.