AssetBundle 注意事项以及使用
AssetBundle是什么
AssetBundle是Unity的资源管理包,用于资源加载卸载。
AssetBundle分为数据头和数据段:
- 数据头:存储一些设置,如压缩类型,索引,manifest等
- 数据段:存储序列化后Asset数据
AssetBundle的优点:
- 自带压缩算法
- 方便管理,适合增量更新
- 可随意加载卸载Asset
- 内部包含Asset的引用关系,不需要怕引用丢失
AssetBundle的压缩
压缩格式分为:LZ4,LZMA
- LZMA打包成字节流,包体会比LZ4小
- LZMA打包运行时占用运行内存空间会比LZ4大很多,在使用是LZMA包在初始化时先解压再压缩成LZ4使用,个人理解实际情况:LZMA解压完的数据会先存在内存中,再压缩成LZ4,但是使用时又需要将LZ4解压,感觉上是极度没必要的。
- 通常情况下使用LZ4打包,不需要考虑太多内存空间的事,只是包体会稍微大一些
AssetBundle的读取
有两种方式LoadFromMemory,LoadFromFile
- LoadFromMemory:需要反复读取byte数组,会有额外的内存消耗
- LoadFromFile: 直接从硬盘文件中读取,注意:LoadFromFile在Editor模式下会直接读取整个AssetBundle,而运行时只会读取AssetBundle的头数据,在Editor下性能分析需要注意这一项
AssetBundle的卸载
AssetBundle.UnLoad(bool unloadAllLoadedObject)
- 卸载时需要注意,当使用UnLoad(false),且有实际使用资源时,该资源并不会卸载会缓存一份,再下一次加载出AssetBundle时,会复制另一份资源,导致同样的资源内存中存在两份。
- 卸载时使用UnLoad(true),会卸载所有加载资源,使用这类资源的将丢失,但是下一次加载出AssetBundle时,内存中只会有一份资源
AssetBundle的依赖关系
编辑器下由AssetDatabase 和 AssetImporter管理,AssetDatabase管理依赖,AssetImporter为AssetBundle数据
- 通过AssetDatabase.GetDependencies(path) 来获取该Asset的依赖文件
- 通过AssetImporter可以修改Asset的AssetBundle设置
- 实际打包时,会将Asset的依赖关系打进manifest文件,但是加载一个AssetBundle时Unity并不会将其依赖AssetBundle一同加载出来,需要自己主动进行管理
AssetBundle在项目中使用
通常在实际项目中使用并不会去手动一一设置AssetBundle名称再进行打包,而会根据项目需求自定义打包模式,下面由我介绍一下个人感觉非常实用的打包策略。
- 将一个文件夹路径下所有的文件统一自动打成AssetBundle包,所有Asset按文件夹名称设置ABName并递归所有子文件夹,使用这种做法只需要管理好项目资源的目录结构就可以很好管理AssetBundle了
- 在打包的同时将保存所有Asset的数据:crc, path, assetName, assetBundleName, dependceAssetBundles。保存成二进制一同打进config包中,游戏启动先加载config,在加载一个资源时再加载对应包以及依赖包即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19[System.Serializable]
public class AssetBundleConfig
{
// 资源路径转crc
public uint crc;
// 资源路径
public string path;
// 资源包名
public string assetBundleName;
// 资源名:从资源包中加载的名称
public string assetName;
// 依赖包
public List<string> dependceAssetBundles;
}
[System.Serializable]
public class AssetBundleContainer
{
public List<AssetBundleConfig> configList;
} - 实现两个管理器AssetBundleManager,以及ResourceManager,使用时ResourceManager按路径加载资源,ResourceManager从AssetBundleManager拿到AssetBundle包
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
31public interface IAssetBundleManager
{
/// <summary>
/// 同步加载AB包
/// </summary>
AssetBundle LoadAssetBundle(string assetBundleName);
/// <summary>
/// 异步加载AB包
/// </summary>
void LoadAssetBundleAsync(string assetBundleName, Action<AssetBundle> callback);
/// <summary>
/// 卸载AB包
/// </summary>
void UnLoadAssetBundle(string assetBundleName);
}
public interface IResourceManager
{
/// <summary>
/// 同步加载资源
/// </summary>
T LoadAsset<T>(string path) where T : UnityEngine.Object;
/// <summary>
/// 异步加载资源
/// </summary>
void LoadAssetAsync(string path, Action<UnityEngine.Object, object> onLoaded, int priority = 0, object userData = null);
/// <summary>
/// 卸载资源
/// </summary>
void UnLoadAsset(string path, bool isDestroy = false);
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Skier!