Addressable是什么

是Unity官方出的资源管理器,Addressable即可寻址的资源系统
Addressable的优点:

  • 通过一个key,可以直接获取资源,不需要在意资源的实际位置
  • 有完整的可视化界面,不需要写大量资源管理代码即可管理资源
  • 方便自定义打包,自带增量更新等

Addressable的使用心得

  • 操作界面入口
    Tools

  • 初次打开需要创建Setting之后会看到Assets目录下的文件结构,先做简单介绍后面在工具使用时会依次讲到所有资源文件使用方式

    路径 注释
    AddressableAssetsData 根目录,AddressableAssetSettings是整个Addressable设置
    AddressableAssetsData/AssetGroups 资源管理组,管理多个Schema处理该组内资源的读取/加载/保存等逻辑
    AddressableAssetsData/AssetGroups/Schemas 处理模式,处理数据的实际逻辑类,继承自AddressableAssetGroupSchema,默认提供了三个Schema,分别对应两个AssetGroups:Built In Data以及Default Local Group
    AddressableAssetsData/AssetGroupTemplates 这个路径下只是一个模板,在创建Group时会复制一份这个模板
    AddressableAssetsData/DataBuilders 在不同构建模式下,在游戏运行中的数据提供者,可选择项有InstanceProvider以及SceneProvider
    AddressableAssetsData/Windows 这个路径是打包才会自动生成的本地对应文件,记录上一次打包信息,可以用于增量更新,通过保存的文件判断哪些文件需要更新
  • Groups界面,管理所有Groups,即资源组,默认资源组存在两个:Build In DataDefault Local Group

    Group 注释
    Build In Data 点击Build In Data,对应Assets/AddressableAssetsData/AssetGroups/Build In Data.asset,只有两个设置:包含Resources路径下资源,BuildSetting设置的场景,即这部分资源会打进游戏包中,不进行资源加载,这个资源组官方已经设置好了,不需要做任何其他设置。 Build In Data.asset目前没有方式主动创建,不要误删即可(不然只能重新创建数据了)。
    Default Local Group 对应Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset,其中包含两个Schema:BundledAssetGroupSchema,ContentUpdateGroupSchema。 ContentUpdateSchema:只有一个设置,设置为全量更新或者增量更新,全量:更新即替换,增量:不替换原资源情况下多打一个资源包,BundledAssetGroupSchema:设置资源打包/加载路径,以及Bundle模式:crc缓存,bundle名,以什么方式分组等,通常使用默认即可
  • Groups界面操作
    资源可以通过拖拽文件夹,拖拽单个文件,或再Inspector面板直接勾选Addressable

    按钮 注释
    Profile 路径配置,远程/本地的加载/构建路径,不管构建再哪个路径底下,加载Key都保持不变,这也是Addressable基本思想所在
    Tools 工具,可以快捷打开所有界面,关于’Check For Content Update’按钮是用于增量更新的,当group设置为增量模式,且相比较上一次存在变换,点击这个按钮增量打包,会产生一个新的资源组管理增量资源,增量打包后原资源不会删除,但对应key下的hash指向的资源会变成新包资源。
    Play Mode Script 游戏中使用的资源加载模式:1.fastest:AssetsDataset加载,2.advanced:模拟ab包加载,3.requires built groups:实际ab包加载。选择每种模式后对应AddressableAssetsData/DataBuilders的构建设置也会修改,对应1.BuildScriptFastMode,2.BuildScriptPackedPlayMode,3.BuildScriptVirtualMode,其中多的一个BuildScriptPackedMode为实现构建资源时的默认构建模式
    Build New Build 下的按钮对应AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset,第二个按钮即增量更新按钮与Tools中的Content Update配合使用,Clean按钮即清除已构建的资源
  • Profile 界面:管理Profile,设置打包,加载等路径

  • AddressableAssetSettings设置:通常使用默认即可,对应按钮名称标记很明显了,不进行详细介绍

  • EventViewer界面:查看运行时资源使用情况,启动时需设置AddressableAssetSettings中的Send Profiler Event

  • Analyze界面:用于分析资源的依赖关系,Fixable Rule:可修复的规则,分析器自动修复,UnFixable Rule:不可修复的规则,会列出来需要手动修复

  • Hosting界面:创建远程或者本地的服务器,方便测试,默认使用HTTP Service,查看HttpHostingService.cs代码可自定义服务器模式

Addressable的使用说明

加载资源

Addressable中加载任何资源都需要异步加载,不过可以使用Task多线程方式加载,使用非常方便。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Test : MonoBehaviour
{
[SerializeField]
private string _entryName = "Assets/Prefabs/Cube.prefab";

public AssetReference ar;

private void Start()
{
// 使用Task异步加载
StartAsync();

// 使用AssetReference引用直接加载
ar.LoadAssetAsync<GameObject>().Completed += LoadFinish;
ar.InstantiateAsync(Vector3.one, Quaternion.identity);
}

private void LoadFinish(AsyncOperationHandle<GameObject> loadHandle)
{
if (loadHandle.IsDone && loadHandle.Status == AsyncOperationStatus.Succeeded)
{
//这里Result是预制体
Debug.Log(loadHandle.Result);
Addressables.Release(loadHandle);
}
}

private async Task StartAsync()
{
var instance = await Addressables.InstantiateAsync(_entryName).Task;
Addressables.ReleaseInstance(instance);
instance = await Addressables.InstantiateAsync(_entryName).Task;
Addressables.ReleaseInstance(instance);
}
}

关于更新

使用Addressables提供的接口即可完成更新检查,以及下载,详细请阅读代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private async void UpdateAndDownLoad()
{
// 1. 检查更新
AsyncOperationHandle<List<string>> updateHandle = Addressables.CheckForCatalogUpdates(false);
await updateHandle.Task;
if (updateHandle.Status == AsyncOperationStatus.Succeeded)
{
updateList = updateHandle.Result;
}

// 2.开始更新
AsyncOperationHandle<List<IResourceLocator>> updateHandler = Addressables.UpdateCatalogs(updateList, false);
await updateHandler.Task;

// 3.获取更新资源的key
List<string> updateKeys = new List<string>();
foreach (IResourceLocator locator in updateHandler.Result)
{
if (locator is ResourceLocationMap map)
{
foreach (var item in map.Locations)
{
if (item.Value.Count == 0) continue;
string key = item.Key.ToString();
if (int.TryParse(key, out int resKey)) continue;

if (!updateKeys.Contains(key))
updateKeys.Add(key);
}
}
}

// 4.判断下载资源大小
AsyncOperationHandle<long> downLoadSize = Addressables.GetDownloadSizeAsync(updateKeys);
await downLoadSize.Task;

// 5.下载
AsyncOperationHandle downLoad = Addressables.DownloadDependenciesAsync(updateKeys, MergeMode.None);
await downLoad.Task;

// 6.清除
Addressables.Release(updateHandler);
Addressables.Release(downLoad);
}

Addressable的扩展

自动化打包

  • 在实际项目中资源打包通常不会人工手动设置,而是通过一些模式自动化打包,Addressable虽然提供了非常完善的功能界面,但是打包自动化还是需要用户自己扩展。以下是我个人理解的打包策略,与上篇AssetBundle文章的一样的策略,一个文件夹下所有的资源都按当前文件夹名称设置AB包一个文件一个AB包,子文件递归设置。
  • Groups界面可以直接拖拽文件夹进去,但是打包设置中只有三个选项:1.一组打成一个包,2.文件夹打成一个包(一次拖进去的文件夹子目录也包括进去),3.按标签打包。我这里使用的是按标签打包,相同标签一个包。
  • 扩展代码请查看末尾的项目。

自动化打包

场景加载以及游戏物体实例化扩展

  • Addressable默认有提供InstanceProvider以及SceneProvider,但是InstanceProvider中并没有使用到对象池,且在使用Addressables.InstantiateAsync()多次后,同样的资源引用会存在多个,可以通过EventViewer中看到资源占用的堆内存空间,通过继承IInstanceProvider以及ISceneProvider自己实现加载完实际资源后的实例化对象即可。其实就是将对象池写入IInstanceProvider,查看末尾的项目代码其中有InstanceProviderHelper.cs实现。

项目路径 https://github.com/Skierhou/ResourceManager