【第一手学习资料】
- Unity Manual
【AssetBundle的作用】
- AssetBundle是一个压缩包包含模型、贴图、预制体、声音、甚至整个场景,可以在游戏运行的时候被加载;
- AssetBundle自身保存着互相的依赖关系;
- 压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网络传输;
- 把一些可以下载内容放在AssetBundle里面,可以减少安装包的大小;
【AssetBundle的定义】
- 1.它是一个存在于硬盘上的文件。可以称之为压缩包。这个压缩包可以认为是一个文件夹,里面包含了多个文件。这些文件可以分为两类:serialized file 和 resource files。(序列化文件和源文件)
serialized file:资源被打碎放在一个对象中,最后统一被写进一个单独的文件(只有一个)
resource files:某些二进制资源(图片、声音)被单独保存,方便快速加载 - 2.它是一个AssetBundle对象,我们可以通过代码从一个特定的压缩包加载出来的对象。这个对象包含了所有我们当初添加到这个压缩包里面的内容,我们可以通过这个对象加载出来使用。
【AssetBundle使用流程】
- 1,指定资源的AssetBundle属性
(xxxa/xxx)这里xxxa会生成目录,名字为xxx - 2,构建AssetBundle包
- 3,上传AB包
- 4,加载AB包和包里面的资源
【2.构建AssetBundle包】
using System.IO;
using UnityEditor;
public class BuildAllAssetBundles
{
[MenuItem("Assets/BuildAllAssetBundles")] //编辑器扩展
static void BuildAssetBundles() {
string path = "AssetBundles";
if(!Directory.Exists(path)) { //判断路径是否存在
Directory.CreateDirectory(path); //生成路径
}
//打包AssetBundle
BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
}
}
【加载本地AB包】
private void Start() {
AssetBundle ab= AssetBundle.LoadFromFile("AssetBundles/scene/cubewall.unity3d");
GameObject[] gos = ab.LoadAllAssets<GameObject>();
foreach(var item in gos) {
Instantiate(item);
}
}
【分组策略(仅供参考)】
- 1,逻辑实体分组
a,一个UI界面或者所有UI界面一个包(这个界面里面的贴图和布局信息一个包)
b,一个角色或者所有角色一个包(这个角色里面的模型和动画一个包)
c,所有的场景所共享的部分一个包(包括贴图和模型) - 2,按照类型分组
所有声音资源打成一个包,所有shader打成一个包,所有模型打成一个包,所有材质打成一个包 - 3,按照使用分组
把在某一时间内使用的所有资源打成一个包。可以按照关卡分,一个关卡所需要的所有资源包括角色、贴图、声音等打成一个包。也可以按照场景分,一个场景所需要的资源一个包
【分组策略 - 总结】
- 1,把经常更新的资源放在一个单独的包里面,跟不经常更新的包分离
- 2,把需要同时加载的资源放在一个包里面
- 3,可以把其他包共享的资源放在一个单独的包里面
- 4,把一些需要同时加载的小资源打包成一个包
- 5,如果对于一个同一个资源有两个版本,可以考虑通过后缀来区分 v1 v2 v3 unity3dv1 unity3dv2
【依赖打包】
- Unity会自动依赖打包,只需要将共享的资源单独一个包。
【压缩包】
//打包AssetBundle
BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
-
1,Build的路径(随意只要是在硬盘上都可以的)
-
2,BuildAssetBundleOptions
BuildAssetBundleOptions.None:使用LZMA算法压缩,压缩的包更小,但是加载时间更长。使用之前需要整体解压。一旦被解压,这个包会使用LZ4重新压缩。使用资源的时候不需要整体解压。在下载的时候可以使用LZMA算法,一旦它被下载了之后,它会使用LZ4算法保存到本地上。
BuildAssetBundleOptions.UncompressedAssetBundle:不压缩,包大,加载快
BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4压缩,压缩率没有LZMA高,但是我们可以加载指定资源而不用解压全部。 -
注意使用LZ4压缩,可以获得可以跟不压缩想媲美的加载速度,而且比不压缩文件要小。
-
BuildTarget:只能在指定平台上加载包
【Manifest 文件】
ManifestFileVersion: 0
CRC: 3828937951 //检验码
Hashes:
AssetFileHash:
serializedVersion: 2
Hash: 413dd6750d8d25a9ba929c870be27ae5
TypeTreeHash:
serializedVersion: 2
Hash: 0615fdd8182050e228ba12bfa176028d
HashAppended: 0
ClassTypes:
- Class: 1
Script: {instanceID: 0}
- Class: 4
Script: {instanceID: 0}
- Class: 21
Script: {instanceID: 0}
- Class: 23
Script: {instanceID: 0}
- Class: 33
Script: {instanceID: 0}
- Class: 43
Script: {instanceID: 0}
- Class: 65
Script: {instanceID: 0}
Assets:
- Assets/Prefabs/cubewall.prefab //AB包里面包括的资源
Dependencies:
- D:/MyGamesProjets/AssetBundleProject/AssetBundles/scene/share.unity3d //依赖的AB包
【本地加载AB包】
方式一:【AssetBundle.LoadFromMemoryAsync】
string path = "AssetBundles/cubewall.unity3d";
IEnumerator Start() { //此方法会自动调用
AssetBundleCreateRequest request= AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
yield return request;
AssetBundle ab = request.assetBundle;
GameObject go = ab.LoadAsset<GameObject>("cubewall");
Instantiate(go);
}
方式二:【AssetBundle.LoadFromFileAsync】
string path = "AssetBundles/cubewall.unity3d";
private IEnumerator Start() {
AssetBundleCreateRequest request= AssetBundle.LoadFromFileAsync(path);
yield return request;
AssetBundle ab = request.assetBundle;
GameObject go = ab.LoadAsset<GameObject>("cubewall");
Instantiate(go);
}
方式三:【WWW.LoadFromCacheOrDownload】本地加载
private IEnumerator Start() {
string wwwPath = @"file:///D:\MyGamesProjets\AssetBundleProject\AssetBundles\cubewall.unity3d";
while(!Caching.ready) { //检查缓存是否完成
yield return null;
}
WWW www= WWW.LoadFromCacheOrDownload(wwwPath, 1);
if(string.IsNullOrEmpty(www.error)) { //判断www读取下载是否有错误
Debug.Log(www.error);
yield return null;
}
var ab= www.assetBundle;
GameObject go = ab.LoadAsset<GameObject>("cubewall");
Instantiate(go);
}
【www.LoadFromCacheOrDownload】网络加载
【在本地建立模拟服务器】
- 在NetBox2.exe 在软件所在目录新建一个index.html文件
- 把Assetbundle资源文件放在软件所在目录下
- 打开NetBox2.exe启动一个服务器(每次都会申请一个新的端口号)
- 就可以通过www网络加载AB包了
string wwwPath = @“http:\127.0.0.1\AssetBundles\cubewall.unity3d”;
string wwwPath = @“http:\host\AssetBundles\cubewall.unity3d”;
方式四:【UnityWebRequest.GetAssetBundle】
private IEnumerator Start() {
//string uri = @"file:///D:\MyGamesProjets\AssetBundleProject\AssetBundles\cubewall.unity3d";
string uri_1 = @"http://localhost:59501/AssetBundles/cubewall.unity3d"; //注意添加端口号
UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri_1);
yield return request.Send(); //此时才开始下载
if(request.isNetworkError) {
Debug.Log(request.error);
} else {
//AssetBundle ab1 = DownloadHandlerAssetBundle.GetContent(request);
AssetBundle ab2 = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
GameObject go = ab2.LoadAsset<GameObject>("cubeWAll");
Instantiate(go);
}
}
【使用AssetBundleManifest】
AssetBundleManifest存在于唯一的那个AssetBundles里面
private void Start() {
AssetBundle ab = AssetBundle.LoadFromFile(@"AssetBundles/cubewall.unity3d");
AssetBundle assetBundle = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");
AssetBundleManifest abm = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] strArry = abm.GetAllDependencies("cubewall.unity3d");
foreach(var item in strArry) {
print(item);
AssetBundle.LoadFromFile(@"AssetBundles/" + item);
}
GameObject go = ab.LoadAsset<GameObject>("CubeWall");
Instantiate(go);
}
【AB资源卸载】
- AssetBundle.Unload(true);强制卸载资源,会造成资源丢失
- AssetBundle.Unload(false);卸载没有被引用的资源,无法自动回收
- Resources.UnloadUnusedAssets--------当必须使用false时可以在确保场景中和代码中都没有引用的时候可以手动清理。
- 或者场景切换时系统会自动调用Resources.UnloadUnusedAssets
【安全性校验】
重用的三种算法:
- CRC
- MD5 04年被山东大学王小云破解了:通过检验值得到数据
- SHA1 安全性最高,安全性越高速度越慢
【重复资源问题】
- 经常更新的资源单独一个包
- 共享的资源打成一个包
- 图集多的时候,不同图集尽量分tag,如果不给tag默认会打成一个包
【可视化AssetBundle操作插件】
- AssetBundles-Browser
在Unity官方的github主页有,地址是:https://github.com/Unity-Technologies/AssetBundles-Browser