Unity 版本:2018.1.3
1、Assetbundle的打包
在Unity5之后的版本。Assetbundle的打包就变的异常方便。不用象以前4.x版本的时代。还需要自己管理引用关系。只要设置好Assetbundle的包名就行。如图:
把Assetbundle的包名设置好之后。调用:
BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform)
其中:
outputPath:Assetbundle的输出路径
BuildAssetBundleOptions :打包的设置枚举,其中最长用的是以下三种:
UncompressedAssetBundle:不压缩, 打包后的文件最大
CompleteAssets:用LZMA格式压缩,打包后的文件最小。但是加载资源的时候。会把这个AssetBundle包解压出来。浪费内存资源
ChunkBasedCompression:用LZ4格式压缩,打包后的文件大于LZMA格式的文件。但远小于不压缩的打包方式。LZ4格式的压缩选项是从5.3之后引入的。支持把资源打成LZ4格式。这样的好处是在加载AssetBundle里面的某个资源时,不用把整个包全部解压就能读取资源。这样增大了AssetBundle包的读取速度也节省了内存
综上,在5.3之后的版本。推荐使用ChunkBasedCompression格式。
打包好的AssetBundle包对应的会生成一个Manifest文件。这个文件包含了交验、依赖文件等信息。可以用做增量更新
除了单个资源对应的Manifest文件。在输出文件夹内会生成一个总的Manifest文件。名称是[文件夹名].Manifest。它包含了所以bundle的信息以及它们之间的相互依赖关系信息。所以我们在加载Bundle文件时。需要提前把总的Manifest文件加载出来。然后通过它来确认bundle之间的依赖
在实际项目中。如果每个资源都资源都手动编辑Assetbundle Name的话会很麻烦。一般Assetbundle包都会包含在文件夹里。还有一些离散的独立文件。基于这个原因。我们可以把文件夹的名称做为包名。独立的文件用自己的文件名称做包名。可以自己写一个工具来批量处理
[MenuItem("Tool/SetAssetBundleName")]
static void SetAssetBundleName()
{
string[] strs = Selection.assetGUIDs;
foreach(var str in strs)
{
string _str = AssetDatabase.GUIDToAssetPath(str);
if (Directory.Exists(_str))
{
string _DirName = Path.GetFileName(_str);
var files = Directory.GetFiles(_str);
foreach (var file in files)
{
if (file.Contains(".meta"))
continue;
AssetImporter asset = AssetImporter.GetAtPath(file);
asset.assetBundleName = _DirName;
asset.SaveAndReimport();
}
}
else
{
if (_str.Contains(".meta"))
continue;
string _DirName = Path.GetFileNameWithoutExtension(_str);
AssetImporter asset = AssetImporter.GetAtPath(_str);
asset.assetBundleName = _DirName;
asset.SaveAndReimport();
}
}
AssetDatabase.Refresh();
}
这样。就能方便的设置包名了
看到这里。估计就能自己写出一个Assetbundle打包的功能。但是,上面说的都是介绍原理。有一个Unity官方提供的工具。功能及其强大。除了批量设置的功能之外。功能全有。
那就是:AssetBundleBrowser。界面如下:
在Build的标签页下面。有可以选择的平台、输出路径和压缩方式。一键搞定
在Configure标签页下面可以看到当前的各个包里面所包含的资源。有重复包含的还能标识出来
2、AssetBundle加载:分为AssetBundle对象的加载和从AssetBundle对象里面加载所需的资源
AssetBundle对象的加载有两种方法
www:
1、直接调用www的构造函数。传入下载路径。等www下载完成之后。www对象包含AssetBundle资源。但是在内存中创建一个较大的webStream(解压后的内容。通常比原Bundle文件大4~5倍)。因此AssetBundle.LoadAsset可以直接在内存中进行
2、使用 WWW LoadFromCacheOrDownload方法,这是个www的静态方法。该方法同样会加载Bundle文件。并返回一个www对象。和上面那个方法不同的是,该方法会将解压后的Bundle文件存在磁盘作为缓存。而非直接在内存中解压。只会在内存里面创建一个较小的SerializedFile。后续的AssetBundle.LoadAsset需要通过IO从磁盘中读取
通过AssetBundle的静态方法直接加载AssetBundle:
1、AssetBundle LoadFromFile,这个是一个同步的方法,针对LZ4压缩和未压缩的bundle文件,该方法会直接加载,对于LZMA压缩的文件,先将bundle·文件解压后再加载。还有一个异步的方法:LoadFromFileAsync
2、AssetBundle LoadFromMemory,这个方法是从内存中获取Bundle的二进制数据。并同步的创建AssetBundle对象,这个方法一般用在自己加密过的AssetBundle包,把原始文件解密之后。用该函数。
上面便是运行时加载AssetBundle对象的方法。下图是Unity3d官方的一个中文版总结:
综上,LoadFromFile方法是最优的加载方式,LoadFromMemory则用于需要加密的AssetBundle包
通过上面的了解。建议项目在以下场景用不一样的方法
1、在随游戏发布的AssetBundle包,存放在StreamingAssets文件夹中:
用LZ4格式压缩打包,在运行时用LoadFromFile方法加载,这样的好处是坚固了包的大小、加载速度和内存消耗
2、一次性更新包:
同上,用LZ4格式压缩打包,在运行时用LoadFromFile方法加载。还有一种方法是用LZMA格式压缩,用WWW.LoadFromCacheOrDownload方法下载并缓存AssetBundle包文件。但是个人不推荐。因为这个虽然减小了需要下载的包大小。但是增加了程序的负责性。需要判断资源是否是更新包从而使用不一样的加载方式
3、实时更新包:
有的数据。更新频率比较快,需要每次使用的时候。才从服务器上下载。这个时候用用LZMA格式压缩,用WWW.LoadFromCacheOrDownload方法下载并缓存AssetBundle包文件。这个是最大的压缩率,减小下载的传输率。同时在本地创建缓存。兼顾了以后的加载速度
4、加密包:
对数据安全比较看重的AssetBundle包。可以用LoadFromMemory方法。先在内存中解密,之后再获取AssetBundle对象
5、自己压缩的AssetBundle
自己用第三方工具压缩生成的AssetBundle包。在打包接口中。选择不压缩的方式。在加载时。选用LoadFromFileAsync函数来进行异步操作
3、从AssetBundle包中加载资源,AssetBundle的加载有以下几种方式:
LoadAsset:从资源包中加载指定的资源
LoadAllAsset:加载当前资源包中所有的资源
LoadAssetAsync:从资源包中异步加载资源
资源卸载用的是Unload方法。传递的参数是一个bool值,当传入false时。仅仅销毁内存中AssetBundle对象包含的资源。当传入是true时。不仅仅销毁内存中的AssetBundle对象。根据AssetBundle·创建出来的对象也会被销毁