什么是AssetBundle?(unity官方文档翻译)
AssetBundle是unity提供的一个特定平台的归档文件(archive file),可以在运行时加载。AssetBundle包可以明确的表示互相之间的依赖关系。例如a包中的材质引用了b包中的贴图。为了在网络上高效的传输。AssetBundle可以更具实际需求选择内置的压缩算法。
AssetBundle对下载DLC很有用,可以减少安装包大小,优化终端平台的资源加载,减少运行时的内存压力。
上面是unity官方文档的翻译,AssetBundle功能总结有:游戏资源更新,减少游戏安装包大小,优化资源加载
如何使用AssetBundle
一、给对象设置AssetBundle属性
首先AssetBundle可以对所有的资源进行打包(预制体,音频,贴图,材质,甚至场景),当你选择对象的时候,如果Inspector上有AssetBundle属性的设置,就说明他可以打包。
第一个None是 包名,也可以是 目录/包名(可以创建目录),第二个None是后缀。这两个属性都是可以自定义的。(这里这个材质的包名是material 后缀是u3d,注意都是强制小写)
二、创建打包工具
当我们把要打包的材质定义好AssetBundle属性之后,就可以开始打包操作了。所有我们这里要先写一个在编辑器模式下运行的打包工具。
using System.IO;
using UnityEditor;
public class CreatAB
{
//在Unity菜单栏Assets列表下面创建一个快捷方法按钮
[MenuItem("Assets/CreatAssetBundles")]
static void CreatAssetBundles()
{
//路径(这是相对路径,项目的跟目录)
string path = "AssetBundless";
//判断路径是否存在
if(!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
//打包
BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
}
}
介绍这里用到的几个方法
Directory.Exists(路径):类方法 判断给定的路径是否是已经存在的目录 是返回true 反之false
Directory.CreateDirectory(路径):类方法 在指定路径下创建一个目录
BuildPipeline.BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform):类方法 在编辑器模式下打包所有指定的AssetBundle对象
- outputPath:输出目录(只能输出到现有目录中)
- assetBundleOptions:包的构建方式(使用那种压缩算法)
- targetPlatform:目标平台(AssetBundle包不是跨平台的,只能在指定平台使用)
- 返回值: AssetBundleManifest类型文件 包含了所有AssetBundle包的列表和依赖关系
写好方法后开始打包,这里我先创建一个Cube,然后将上面那个指定了AssetBundle属性的材质给到Cube,再把这个Cube做成预制体,并给这个Cube设置一下AssetBundle属性(包名是cube,后缀是u3d)
三、打包
我们直接选择Assets找到CreatAssetBundles点击,等待一下就可以了,然后我们看一下打包文件夹里面有些文件。直接打开项目的根目录有一个AssetBundles文件夹,打开他可以看到下面的6个文件。先从后缀上看,一种是我们设置的u3d的后缀结尾的文件,一种是Manifest后缀结尾的文件。
- .u3d 结尾的文件是Assetbundle包本体
- .Manifest 结尾的文件是给人看的,让我们查看包的属性,这个文件可以直接用记事本打开,可以查询效验码、包里包含的资源对象,包的依赖关系,
- AssetBundle.Manifest 中包含的是所有包的信息 给人看的
- AssetBundle 这个种也包含的是所有包的信息 只不过这个文件是计算机看的 就是打包方法BuildPipeline.BuildAssetBundles的返回值
四、使用AssetBundle包
使用AssetBundle包的API有好几种,这里介绍的是既可以从本地加载也可以从服务器加载的一种方法
UnityWebRequest 异步方法(更多方法查看Unity官方手册)
先创建一个脚本,然后把脚本挂在到一个空物体上,编辑脚本
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class LoadAssetBundleFile : MonoBehaviour
{
private void Start()
{
StartCoroutine("UWR");
}
//异步加载方法需要使用协程
IEnumerator UWR()
{
//路径 可以本地也可以服务器 本地需要加前缀file:///
string [email protected]"file///F:\Unity Test\CSDN__Blog\AssetBundles\cube.u3d";
//创建下载资源请求
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(path);
//开始异步下载资源并等待完成
yield return request.SendWebRequest();
//取得下载好的资源中的AB包(第一种) DownloadHandlerAssetBundled.GetContent方法
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
//取得下载好的资源种的AB包(第二种) 格式转换
//AssetBundle ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
//使用AB包 LoadAsset<对象类型>(对象名)
GameObject cube = ab.LoadAsset<GameObject>("Cube");
Instantiate(cube);
}
}
运行后会发现Cube被实例化出来但是缺少材质,这是因为我们没有加载材质的AssetBundle包,这就关系到AssetBundle打包时的依赖关系:上面这个例子中我们分别把cube的预制体和他所使用的材质进行的打包,所以在我们单独使用cube预制体的ab包时就是没有材质的,但是如果我们将材质的AssetBundle属性设为None,再进行打包。之后我们在次运行同样的代码,实例化出来的cube就会带有材质。
这就说明当你给自身使用的材质设置了AssetBundle属性并打包后,cueb的ab包就不会包含他自身使用材质的数据,这时cube的ab包和材质的ab包就建立了依赖关系。如果没有打包你使用的材质的,那么cube包就会自带材质的数据,这一点对比下面这个没有单独打包材质的cube大小和上图cube的大小就知道了(适用于所有可以打包的对象)。
(依赖打包只需要将依赖的资源打包,就可以建立依赖关系(这是unity控制的),这种做法可以避免出现重复资源的打包)
那么如何再脚本里获取不同包之间的依赖关系呢?这就要用到 AssetBundles文件 我们先把材质的AssetBundls的属性设置回来然后重新打包。之后运行发现cube还是没有材质的,让后我们加上这段代码。再次运行就已经有材质了。
//取得AB包的依赖关系
//首先拿到AssetBundles文件 (这是最简单的加载AB包方式,返回值就是加载的ab包 属于同步加载)
AssetBundle manifestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
//拿到AssetBundles文件中的manifest文件
AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//取得对应AB包的依赖关系
//GetAllDependencies(AB包名) 返回值是这个AB包所依赖的所有AB包包名
string[] strs = manifest.GetAllDependencies("cube.u3d");
foreach (string name in strs)
{
//加载cubeAB包所依赖的所有资源,这里就只有一个材质资源
AssetBundle.LoadFromFile("AssetBundles/" + name);
}
这里的加载或者上面说的下载都是一个意思,是指将AB包中的数据存到内存中,但什么时候使用要看代码的调度,既有手动比如实例化cube,也有自动比如cube自动找到内存上的材质并使用。
(注意:如果一个资源有依赖资源,在使用这个资源前要最好先加载他的依赖资源,实测是不用的,这里我们就是后加载的,但是逻辑上最好还是遵守避免出现不必要的错误)
AssetBundle打包策略
- 把经常更新的资源放在一个单独的包,不经常跟新的放一个包
- 需要同时加载的资源放一个包
- 共享的资源单独放一个包
- 一个场景可以内用的资源可以放一个包
- 等等 这些策略都是更具项目需要灵活调整的
分享让知识变得有意义!后续会继续更新一些学习中问题。
OJMars
InTheMars