AssetBundle
AssetBundle简介
什么是AssetBundle?
AssetBundle我们简称其为AB包,它是一个用于特定平台的资产压缩包,有点类似于压缩文件。这里的资产包括:模型,贴图,预制体,材质球等。因此AB包的作用实际上和Resources文件夹的作用是很像的。但两者之间有很大的不同。Resources文件夹在打包的时候其中的内容就定死了,只读没有办法修改,而AB包却可以自定义存储位置,自定义压缩方式,以及最重要的它可以有后续的更新。
AB包除了可以减少包体大小之外最大的好处就是使用AB包我们可以实现资源的热更新。
热更新基本规则
- 带有少量默认资源的客户端首先前往服务器端获取资源服务器地址。
- 通过资源对比文件检测需要更新的内容。
- 下载需要的AB包。
打包AB包
- 安装AssetBundleBrowser,对于2019版本之后的unity可以在window选择项中的PackageManager中搜索下载。对于2019版本之前的unity需要去官方的GitHub上下载解压。
- 安装完成后可以在Windows选择项中看到AssetBundleBrowser,点开即可使用。
- 点开之后我们发现里面没有创建AB包的选择项,这里创建AB包需要在资源的inspector面板中创建,点开一个资源,在Inspector面板最下面有AB包的相关设置,其中第一个为要打包的名字,第二个是AssetBundleVariant,主要用于不同版本资源的使用和动态替换。这里我们选择new起名为firstAB,之后来到AssetBundleBrowser就可以看到我们预设置好的一个AB包了。
- 之后我们可以在Build选项中对AB进行打包设置
从上到下分别为:
- Build Target:包的目标平台。
- Output Path:目标输出路径。
- Clear Folders:每次重新打包的时候是否清空文件夹。(这样可以把每次不用的资源清除掉)
- Copy To StreamingAssets:是否将包复制到StreamingAssets文件夹下。
- Compression:AB包压缩方式。
- ETI(Exclude Type Information):资源包中是否包含资源的类型信息。
- FR(Force Rebuild):重新打包时是否重新构建包。
- ITTC(Ignore Type Tree Changes):忽略类型树的改变。
- Append Hash:将文件的哈希值附加到资源包名上。
- Strict Mode:严格模式,如果打包出错了将不会打包成功。
- Dry Run Build:运行时构建。
使用AB包
同步加载AB包
void Start()
{
//1. 加载ab包
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "firstab");
//2. 非泛型加载资源,对于同名不同类型的情况可以指定类型进行加载
GameObject go = ab.LoadAsset("Cube", typeof(GameObject)) as GameObject;
//3. 泛型加载资源
GameObject go2 = ab.LoadAsset<GameObject>("Cube");
//4. 创建资源
Instantiate(go2);
//释放ab包,参数true为释放ab包的同时删除所有和ab包相关的资源;
//false为只释放ab包
ab.Unload(false);
//释放所有ab包,参数true为释放ab包的同时删除所有和ab包相关的资源;
//false为只释放ab包
AssetBundle.UnloadAllAssetBundles(false);
}
注意:同一个AB包不能重复加载。
异步加载AB包
/// <summary>
/// 由于协程的特殊性,所以我们用一个函数来接受来自协程的结果
/// </summary>
/// <param name="abr">异步加载完成后的资源</param>
private void AsyncHandler(AssetBundleRequest abr)
{
print(abr.asset.name);
}
/// <summary>
/// 异步加载AB包
/// </summary>
/// <param name="func">接受来自协程的结果的函数,默认不传</param>
private IEnumerator LoadAsync(Action<AssetBundleRequest> func = null)
{
//异步加载AB包的类型不同于同步加载
AssetBundleCreateRequest ab = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + "firstab");
yield return ab;
//异步加载的资源类型不同于同步加载
AssetBundleRequest abr = ab.assetBundle.LoadAssetAsync<GameObject>("Cube");
yield return abr;
//如果函数不为空则调用
func?.Invoke(abr);
}
AB包依赖
一个包里面的资源使用到了另一个包里面的资源我们就说这两个包产生了依赖。当两个AB包产生依赖后,如果我们只加载其中一个AB包,则有可能会出现资源丢失的情况,这时候需要把依赖包一起加进来才可以。
但问题是一个包可能会依赖多个包,我们对于一个大型项目,要一个一个自己添加依赖包是不现实的,这时候我们就要用到我们的AB主包来解决这个问题。
//加载主包
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "StandaloneWindows");
//获得主包的表单
AssetBundleManifest abList = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//从表单上获得name资源的所有依赖包的名称
string[] maniFestList = abList.GetAllDependencies("Cube");
//循环导入所有依赖包
foreach (var VARIABLE in maniFestList)
{
AssetBundle ab2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + VARIABLE);
}