前言
在Unity中也许大家都听过AB包这种加载资源的方法,但是可能都觉得很难,然后就不去学了,觉得自己写一个小项目怎么都用不到AB包,但是实际上并不是这样,AB包在个人项目中也会有很有趣的应用。
Unity的AB包详解
概念解释
首先,Unity的AB包全称是AssetBundle,是Unity提供的一个用于储存资源的压缩包。
Unity中的AssetBundle系统是对资源管理的一种扩展,通过将资源分布在不同的AB包中可以最大程度地减少运行时的内存压力,可以动态地加载和卸载AB包,使其有选择地加载内容。
AB包与Resources的对比区别
|
AB包 |
Resources |
资源分布 |
可以分布在不同的包中 |
只能生成一个大包 |
存储位置 |
自定义路径 |
只能存在于Resources文件夹中 |
压缩方式 |
压缩方式可选(LZMA,LZ4) |
资源全部压缩为二进制 |
更新方式 |
可以支持后期更新 |
打包后变为可读不可后期更新 |
AB包的特性
- 不可重复加载,只有卸载之后次啊可以再次加载
- 不可打包代码,AB包可以存储大部分的Unity资源,但是不可以直接存储C#脚本,脚本的热更新可以用Lua或者存储打包后的DLL文件
- 打包完成后,会自动生成一个主包(主包名称随平台不同而不同),主包的manifest下会存储有版本号、校验码(CRC)、所有其它包的相关信息(名称、依赖关系)
AB包的常用API
1 2 3 4 5 6 7 8 9 10 11 12 13
|
AssetBundle ab = AssetBundle.LoadFromFile(path);
T obj = ab.LoadAsset<T>(ResourceName); Object obj = ab.LoadAsset(ResourceName); Object obj = ab.LoadAsset(ResourceName,Type); T obj = ab.LoadAssetAsync<T>(resName); Object obj = ab.LoadAssetAsync(resName); Object obj = ab.LoadAssetAsync(resName,Type);
ab.UnLoad(false); AssetBundle.UnloadAllAssetBundles(false);
|
AB包的基本步骤
- 加载资源所在AB包及其的所有依赖包(根据主包的manifest信息找依赖包名称)
- 从AB包中加载指定的资源(根据名称,类型)
- 不再使用时卸载已经加载了的AB包
AB包简单管理系统
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
| using System; using System.Net.Mime; using System.Collections; using System.Collections.Generic; using UnityEngine;
namespace Common { public class ABManager : MonoSingleton<ABManager> { private Dictionary<string, AssetBundle> abCache;
private AssetBundle mainAB = null;
private AssetBundleManifest mainManifest = null;
private string basePath { get { #if UNITY_EDITOR || UNITY_STANDALONE return Application.dataPath + "/StreamingAssets/"; #elif UNITY_IPHONE return Application.dataPath + "/Raw/"; #elif UNITY_ANDROID return Application.dataPath + "!/assets/"; #endif } } private string mainABName { get { #if UNITY_EDITOR || UNITY_STANDALONE return "StandaloneWindows"; #elif UNITY_IPHONE return "IOS"; #elif UNITY_ANDROID return "Android"; #endif } }
protected override void Init() { base.Init(); abCache = new Dictionary<string, AssetBundle>(); }
private AssetBundle LoadABPackage(string abName) { AssetBundle ab; if (mainAB == null) { mainAB = AssetBundle.LoadFromFile(basePath + mainABName); mainManifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); } string[] dependencies = mainManifest.GetAllDependencies(abName); for (int i = 0; i < dependencies.Length; i++) { if (!abCache.ContainsKey(dependencies[i])) { ab = AssetBundle.LoadFromFile(basePath + dependencies[i]); abCache.Add(dependencies[i], ab); } } if (abCache.ContainsKey(abName)) return abCache[abName]; else { ab = AssetBundle.LoadFromFile(basePath + abName); abCache.Add(abName, ab); return ab; }
} #region 同步加载的三个重载 public T LoadResource<T>(string abName,string resName)where T:Object { AssetBundle ab = LoadABPackage(abName);
return ab.LoadAsset<T>(resName); }
public Object LoadResource(string abName,string resName) { AssetBundle ab = LoadABPackage(abName);
return ab.LoadAsset(resName); } public Object LoadResource(string abName, string resName,System.Type type) { AssetBundle ab = LoadABPackage(abName);
return ab.LoadAsset(resName,type); }
#endregion
public void LoadResourceAsync(string abName,string resName, System.Action<Object> finishLoadObjectHandler) { AssetBundle ab = LoadABPackage(abName); StartCoroutine(LoadRes(ab,resName,finishLoadObjectHandler)); }
private IEnumerator LoadRes(AssetBundle ab,string resName, System.Action<Object> finishLoadObjectHandler) { if (ab == null) yield break; AssetBundleRequest abr = ab.LoadAssetAsync(resName); yield return abr; finishLoadObjectHandler(abr.asset); } public void LoadResourceAsync(string abName, string resName,System.Type type, System.Action<Object> finishLoadObjectHandler) { AssetBundle ab = LoadABPackage(abName); StartCoroutine(LoadRes(ab, resName,type, finishLoadObjectHandler)); } private IEnumerator LoadRes(AssetBundle ab, string resName,System.Type type, System.Action<Object> finishLoadObjectHandler) { if (ab == null) yield break; AssetBundleRequest abr = ab.LoadAssetAsync(resName,type); yield return abr; finishLoadObjectHandler(abr.asset); }
public void LoadResourceAsync<T>(string abName, string resName, System.Action<Object> finishLoadObjectHandler)where T:Object { AssetBundle ab = LoadABPackage(abName); StartCoroutine(LoadRes<T>(ab, resName, finishLoadObjectHandler)); }
private IEnumerator LoadRes<T>(AssetBundle ab, string resName, System.Action<Object> finishLoadObjectHandler)where T:Object { if (ab == null) yield break; AssetBundleRequest abr = ab.LoadAssetAsync<T>(resName); yield return abr; finishLoadObjectHandler(abr.asset as T); }
public void UnLoad(string abName) { if(abCache.ContainsKey(abName)) { abCache[abName].Unload(false); abCache.Remove(abName); } }
public void UnLoadAll() { AssetBundle.UnloadAllAssetBundles(false); abCache.Clear(); mainAB = null; mainManifest = null; } } }
|
这里继承的单例脚本可以在我之前的博客中的实用技巧中找到。
AB包的压缩方式
三种压缩方式
- NoCompression:不压缩,解压快,包较大,不建议使用。
- LZMA: 压缩最小,解压慢,用一个资源要解压包下所有资源。
- LZ4: 压缩稍大,解压快,用什么解压什么,内存占用低,更建议使用。
AB包的工作全流程
可以借助Unity官方提供的包管理插件AssetBundle Browser来完成
https://github.com/Unity-Technologies/AssetBundles-Browser
- 在需要打包的资源的Inspector面板下方即可选择其应放在哪个AB包下,也可通过New新建AB包将资源放入,放入后再次Build打包即可将此资源打入相应的AB包中。
- 在Windows中可以打开AssetBundle Browser来看具体打包信息。
- 使用AB包的API来完成资源的自定义加载。