抖音开放平台Logo
开发者文档
控制台

使用 Addressable 进行资源按需加载

收藏
我的收藏
对于小游戏情况而言,需做到即点即玩,即尽可能缩短玩家进入首场景之前的等待时间,因此分包是必须要做的一个环节,本文将介绍Addressable资源管理系统。

一. Addressable概述

Addressable是由Unity官方在2019版本,正式发布的一种资源管理系统,Addressable是Unity官方对AssetBundle的一种封装,目的是为了填补一些AssetBundle缺失的功能,封装一些资源加载的固有功能,从而降低资源加载的使用门槛和后期维护所消耗的精力。
相较于AssetBundle而言,Addressable封装了以下几个功能
    可视化UI界面,关于资源的分组及其他情况更加直观
    自动依赖管理,相较于AssetBundle手动保证某资源的依赖需提前加载进内存,Addressable在开发时无需关注资源依赖情况,当作所有依赖都已经被加载进内存处理,在运行时会自动检测其依赖并自动加载,从而保证每次资源加载都能成功。
    封装网络请求接口,相较于AssetBundle需要手动实现远程bundle的网络请求,Addressable在开发时无需关注资源在本地或者在cdn,统一调用LoadAssetAsync等异步接口处理处理,在运行时会自动下载远程或加载本地。
    资源分析工具,相较于AssetBundle需要手动检测多依赖下的资源重复打包问题,Addressable提供了资源检测工具自动分析重复情况。同时还提供Event Viewer来检测资源加载情况,供优化使用。
如今而言,Addressable是现在游戏作为分包的首选方案。

二. Addressables的加载流程

Addressable一般在构建之后会出现几个文件
    catalog.json:资源表,存放了addressable的所有资源
    setting.json:运行时addressable参数
    {bundle_name}.bundle:bundle包文件
对于所有Asset都是由ResourceManager来管理的
对于每一个资源都分别继承了IResourceLocationIResourceProvider
    IResourceLocation:包含了该资源的所有信息,包括依赖信息,location哈希等。
    IResourceProvider:包含资源的加载和卸载方式,主要是为了统一本地和远程的区别。
在刚进入游戏时,Addressable会做以下操作:
    加载Setting.json,并根据哈希值判断catalog.json是否有更新
    加载最新catalog.json文件,并替换本地catalog缓存
    解析catalog.json文件,读取其中所有的IResourceLocation信息,并保存到ResourceManager
一次运行时资源加载会做以下操作:
    通过IResourceLocation获取该资源的依赖信息及文件hash信息
    通过IResourceProvider获取该资源所属bundle包的加载方式
    如果所属bundle在本地,则直接加载
    如果所属bundle包在云端,则启用网络请求下载,下载完成后再加载
    将加载的资源赋值给AsyncOperationHandle.Result并 设置AsyncOperationHandle.Statue并执行Completed事件

三. Addressables简单例子

AssetReferences 支持拖放和对象选择器分配,这可以使它们更方便地在 Editor Inspector 中使用。
public class LoadAssetScript : MonoBehaviour { public AssetReference somePrefab; private void Start() { somePrefab.InstantiateAsync().Completed += (obj) => { // 加载完成回调 if (obj.Status == AsyncOperationStatus.Succeeded) { Debug.Log("successful"); } }; } } //协程写法 public class LoadAssetScript : MonoBehaviour { public AssetReference somePrefab; private IEnumerator spawnSomathing() { var hanle = somePrefab.InstantiateAsync(); while(!handle.IsDone) {yield return null;} // 加载完成回调 var gameObject = hanle.Result; } }
简单的异步加载接口Addressables.LoadAssetAsync例子
void Start() { StartCoroutine(Load()); Addressables.LoadAssetAsync<GameObject>("Assets/Image.prefab").Completed += (handle) => { if(handle.Status == AsyncOperationStatus.Succeeded){ Instantiate(handle.Result); } }; } //协程写法 IEnumerator Load() { var handle = Addressables.LoadAssetAsync<GameObject>("Assets/Image.prefab"); if (!handle.IsDone) { yield return handle; } if (handle.Status == AsyncOperationStatus.Succeeded) { Instantiate(handle.Result); } }

四. 资源卸载

可以使用Addressables.Release方法对某一个资源进行卸载,此时该资源不会立刻从内存退出
    调用后引用记数会减1,当资源的引用记数为0时,此时该资源仍然不会从内存退出
    等到该资源所属bundle的所有资源的引用计数全为0时,该bundle及包含的所有资源从内存退出
//这是一个Addressable handle卸载的简单例子 Addressables.LoadAssetAsync<GameObject>("Assets/Image.prefab").Completed += (handle) => { if(handle.Status == AsyncOperationStatus.Succeeded){ Instantiate(handle.Result); } Addressables.Release(handle); };

五. Addressable配置简介

5.1 Group

Addressable在打包时是以Group为单位的,一个Group会打包成一个Bundle,同时在资源加载时,当需要加载某一个资源,会一次性将该资源所属的整个bundle包读取进内存,对于某一个资源的依赖资源,也会读取依赖资源所属的bundle包,因此,做好合理的资源分组非常重要

5.2 Profiles

Profiles中记录了构建和加载的路径,包括本地和远程。在运行时调用Addressables.LoadAssetAsync会自动请求此处设置的地址

5.3 Analyzer

Analyzer会通过一个模拟构建,扫描所有Addressable的group,从而分析其中的资源冗余及共享依赖问题,关于具体实现可以参考Unity手游实战:从0开始SLG——资源管理系统-Addressable中文手册(五)分析器(完)

5.4 Event Viewer

该项可以监视Addressables资源的内存管理情况,供性能优化及调试时使用。详细信息可以参考https://zhuanlan.zhihu.com/p/502115922