0%

Unity-AssetBundle

AssetBundle 简介

AssetBundle 是一个存档文件,包含可在运行时加载的特定平台资源(模型、纹理、预制体、音频、甚至整个场景,除了C#脚本)。

AssetBundle 可以表达彼此之间的依赖关系;例如 AssetBundle A 中的材质可以引用 AssetBundle B 中的纹理。

为了通过网络进行有效传递,可以根据用例需求选用内置算法来压缩 AssetBundle(LZMA 和 LZ4)。

AssetBundle 可用于可下载内容(DLC,又称追加内容下载包),减小初始安装大小,加载针对最终用户平台优化的资源以及减轻运行时内存压力。

AssetBundle 资源打包

  1. 资源标签的设置

在 Unity 环境内,除 C#脚本文件以外,选中任何文件后,在 Inspector 面板的下方 Asset Labels 功能区域可以给资源设置 AssetBundle 的文件路径和文件后缀。

资源标签的设置

  1. 创建 AssetBundle

在5.3版本以上,Unity提供了唯一的API来打包AssetBundle,即:

1
2
3
4
BuildPipeline.BuildAssetBundles(string outputPath,
BuildAssetBundleOptions assetBundleOptions,
BuildTarget targetPlatform
);
  • outputPath:资源包的输出路径,资源会被编译保存到存在的文件夹里,注意编译的时候不会自动创建文件夹。
  • assetBundleOptions:资源包编译选项,默认为None。
  • targetPlatform:目标编译平台

使用 Unity 编辑器扩展,进行 AssetBundle 资源打包,将其保存在 StreamingAssets 文件夹中。

1
2
3
4
5
6
7
8
9
10
11
12
// AssetBundlePacker.cs
using System.Collections;
using UnityEngine;
using UnityEditor;

public class AssetBundlePacker {
[MenuItem("AssetBundlePacker/DoPacker")]
public static void DoPacker() {
string path = Application.streamingAssetsPath;
BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
}
}

打包结果
资源打包结果

StreamingAssets、StreamingAssets.manifest 是什么文件?

StreamingAssets.manifest 文件是用于专门存储打包后的 AssetBundle 文件的基本信息的。主要包含以下信息:
CRC 校验码:类似于 MD5,用于计算出该资源的一个特殊信息标示;
ClassTypes 列表:当前资源关联使用到了Unity 中的哪些类,这些类是以编号索引的形式存在的,每个编号都对应一个类文件。

StreamingAssets 是包含 StreamingAssets.manifest 的 AssetBundle 文件。

下载 AssetBundle

下载 AssetBundle 有两种方法:缓存机制和非缓存机制。

不使用缓存

先获取WWW对象,再通过WWW.assetBundle来加载AssetBundle对象,此方法是使用一个新建的WWW对象。AssetBundles并不会缓存到Unity在本地设备存储器上的缓存文件夹中。

使用缓存

通过LoadFromFile、LoadFromMemory方法来下载AssetBundle文件,下载完成后自动被保存在Unity引擎特定的缓存区内。LoadFromFile从磁盘上的文件同步加载AssetBundle,该功能支持任何压缩类型的压缩包。

AssetBundle 加载

当把AssetBundle文件从服务器端下载到本地后,需要把下载好的AssetBundle中的内容加载到内存里并创建AssetBundle文件中的对象。

  • AssetBundle.LoadAsset
  • AssetBundle.LoadAssetAsync
  • AssetBundle.LoadAllAssets

本地加载

加载存放在 StreamingAssets 文件夹中的 AssetBundle 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
...

public class InitGame : MonoBehaviour {

void Start () {
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/prefabs/shapes.ab");
GameObject cube = ab.LoadAsset<GameObject>("Cube");

Instantiate(cube);
GameObject capsule = ab.LoadAsset<GameObject>("Capsule");
Instantiate(capsule);
}
}

远程加载

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
using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Experimental.Networking;

public class DownLoadAssetBundle : MonoBehaviour {

private string mainAssetBundleURL = @"http://www.mynet.com/Assets/AssetBundles/Main";
private string allAssetBundleURL = @"http://www.mynet.com/Assets/AssetBundles/";

void Start() {
StartCoroutine("DownLoadMainAssetBundle");
}

// 下载主[目录]AssetBundle文件.
IEnumerator DownLoadMainAssetBundle() {
UnityWebRequest request = UnityWebRequest.GetAssetBundle(mainAssetBundleURL);
yield return request.Send();
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
AssetBundleManifest manifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] names = manifest.GetAllAssetBundles();
for (int i = 0; i < names.Length; i++) {
Debug.Log(allAssetBundleURL + names[i]);
//StartCoroutine(DownLoadSingleAssetBundle(allAssetBundleURL + names[i]));
StartCoroutine(DownLoadAssetBundleAndSave(allAssetBundleURL + names[i]));
}
}

/// 下载单个AssetBundle文件.
IEnumerator DownLoadSingleAssetBundle(string url) {
UnityWebRequest request = UnityWebRequest.GetAssetBundle(url);
yield return request.Send();
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
string[] names = ab.GetAllAssetNames();
for (int i = 0; i < names.Length; i++) {
string tempName = Path.GetFileNameWithoutExtension(names[i]);
//Debug.Log(tempName);
GameObject obj = ab.LoadAsset<GameObject>(tempName);
GameObject.Instantiate<GameObject>(obj);
}
}

// 下载AssetBundle并且保存到本地.
IEnumerator DownLoadAssetBundleAndSave(string url) {
WWW www = new WWW(url);
yield return www;
if (www.isDone) {
//使用IO技术将www对象存储到本地.
SaveAssetBundle(Path.GetFileName(url), www.bytes, www.bytes.Length);
}
}

// 存储AssetBundle为本地文件.
private void SaveAssetBundle(string fileName, byte[] bytes, int count) {
FileInfo fileInfo = new FileInfo(Application.streamingAssetsPath + "//" + fileName);
FileStream fs = fileInfo.Create();
fs.Write(bytes, 0, count);
fs.Flush();
fs.Close();
fs.Dispose();
Debug.Log(fileName + "下载完毕~~~");
}
}

AssetBundle 卸载

使用AssetBundle.Unload方法来卸载AssetBundle创建出的对象。

  1. AssetBundle.Unload(false):释放AssetBundle文件内存镜像,但不销毁已经加载好的Assets对象;
  2. AssetBundle.Unload(true):释放AssetBundle文件内存镜像同时销毁所有已经加载的Assets对象。