【教程】Unity AssetBundle 资源管理方法
开发平台:Unity 2020版本以上
编程平台:Visual Studio 2022
一、前言
在 Unity 中,“资源管理与使用” 是开发者必修内容。受限制于 项目目标平台、用户设备类型 等因素,资管管理方案不一。本文重点记录 Unity - AssetBundle 资源加载模式。
二、Resourse 与 AssetBundle
2.1 Resources 资源管理方式
- 无法对 Component、GameObject 等对象做到 “即用即卸载”,最终将影响运行时内存占用与其他性能开销。
- Resources 内所有资产将被 Unity 构建过程中打入应用体量内,对于大型资产的项目中进行资产更新将是困难的。
2.2 选择 AssetBundle 的理由
- 有效解决商业项目中初次 "下载体量大"的特点。
- 参考《小鳄鱼爱洗澡》以抢先体验前几关,后续游玩采取 "逐关下载,快速体验" 的策略。
该策略让用户无需等待太长时间即可体验内容,进而更可能保留用户群体。
- 参考《小鳄鱼爱洗澡》以抢先体验前几关,后续游玩采取 "逐关下载,快速体验" 的策略。
- 设备内存管理优异,设备表现上优异。
三、资产加载 | AssetBundle
1)本地加载 AssetBundle 资产
string path = $"{Application.streamingAssetsPath}/Cube";
string modelName = "cube";public void Start() {AssetBundle thisAB = AssetBundle.LoadFromFile(path);GameObject thisAsset = thisAB.LoadAsset<GameObject>(modelName );MonoBehaviour.Instantiate(thisAsset);
}
2)使用 UnityWebRequestAssetBundle 加载 AssetBundle 资源
string downloadURL = $" --------------------------------------- ";
string modelName = $" ---------------------- ";private IEnumerator Start() {var thisRequst = UnityWebRequestAssetBundle.GetAssetBundle(downloadURL);yield return thisRequest.SendWebReqeust();AssetBundle thisBundle = DownLoadHandlerAssetBundle.GetContent(thisRequest);var thisLoadAsset = bundle.LoadAssetAsync<GameObject>(modelName);yield return loadAsset;Instantiate(loadAsset.asset);
}
3)异步加载资源
在这里插入代码片
四、依赖资产 | AssetBundle
在修改部分资源内容时,会出现资源依赖关系丢失的问题,例如 Material、Mesh 等。为防止各资源包中的引用丢失情况,提出加载前优先加载关联资源后再加载本资源对象。
除游戏对象生成的 assetbundle 文件,还会额外生成该目录下的 assetbundle 文件。该文件记录本次输出 assetbundle 对象群的所有外部依赖关联信息。例如在 StreamingAssets 目录下输出 Cube 的 assetbundle 文件,会额外产出命名 StreamingAssets.aseebundle
文件。
示例代码:
string manifestPath = $"{Application.streamingAssetsPath}/StreamingAssets";
string path = $"{Application.streamingAssetsPath}/cube";
string modelName = "cube"void Start() {// 加载依赖AssetBundle thisABDep = AssetBundle.LoadFromFile(manifestPath);var manifest = thisABDep.LoadAsset<AssetBundleManifest>("AssetBundleManifest");string[] dependcies = manifest.GetAllDependencies("cube");Array.ForEach(dependcies, e => AssetBundle.LoadFromFile($"{Application.streamingAssetsPath}/{e}"));// 加载模型var assetGameObject = thisAB.LoadAsset<GameObject>("cube");MonoBehaviour.Instantiate(assetGameObject);// 加载资产依赖资产Array.ForEach(dependcies, e => AssetBundle.LoadFromFile(e));
}
![]() | ![]() |
4.1 加载 Manifest
AssetBundle thisABDep = AssetBundle.LoadFromFile(manifestPath);
manifestPath
是 AssetBundle - Browsers 本次导出所有资产的依赖关系文件。- 该 Manifest 文件名以存储目录文件名为命名,并规定存储在该目录文件夹内。
4.2 AssetBundleManifest | 跳转
var manifest = thisABDep.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
- 这段代码获取依赖信息下关于
AssetBundleManifest
的信息内容,详细参考上 图2。
五、资产加载 | 流程
5.1 关于存储数据结构
使用环境中,多为单场景跳转时对上一场景的加载资源进行卸载,并准备当前场景的资源加载。而 AssetBundle 包加载 禁止重复加载。为管理与校验是否多次加载。需要定义数据结构管理已加载的 AssetBundle 对象。
public Dictionary<string, AssetBundle> AssetBundleDic { get; set; } = new();
- 此处使用
Dictionary
作为 AssetBundle 管理
5.2 关于主要包体(可选)
public AssetBundle MainAssetBundle;
即所有 AssetBundle 的依赖关系包对象。参考 [本博文] 4.2 AssetBundleManifest 的解释。 该 AssetBundle 包体仅需加载一次即可。故作为单独使用。当然通过 Dictionary
中判断是否加载也可。
5.3 关于多平台下包名差异
public string MainAssetBundle {get {
#if UNITY_IOSreturn "Ios";
#elif UNITY_ANDROIDreturn "Android";
#else return "Windows"
#endif}
}
- 对于多平台发布会涉及 AssetBundle 不一的情况,考虑主依赖包信息的命名差别,使用 宏定义。
- 参考 [本博文] 4.1 加载Manifest 加载所有依赖项。
5.4 关于卸载
当 GameObject 被实例化至场景后,该 AssetBundle 内资产将被记入内存中。执行 UnLoad
后,并不影响已实例化在场景内的所有资源。