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
    31
    public 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);
    }

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