AssetBundle资源加载
一个AssetBundle中包含两部分:数据头和数据段。
通过AssetBundle加载游戏资源,分为三步:
-
加载AssetBundle对象。
-
通过AssetBundle对象加载需要的资源。
- 对于非引用类型的资源,还需通过GameObject.Instantiate()创建clone。
1. 加载AssetBundle对象方式
- AssetBundle.LoadFromMemory(可选择异步模式)
- AssetBundle.LoadFromFile(可选择异步模式)
- AssetBundle.LoadFromStream(可选择异步模式)
- UnityWebRequest的DownloadHandlerAssetBundle (异步模式)
- WWW.LoadFromCacheOrDownload (Unity 5.6以及更低版本)(异步模式)
- WWW(异步模式)
1.1 WWW.LoadFromCacheOrDownload(异步-缓存机制),2017以后被废弃。
Unity5.2之前推荐使用 WWW.LoadFromCacheOrDownload(),从2017开始被整合到UnityWebRequest中。以下适用于5.6以前版本。(异步加载,每次打包都需要更新资源版本,保存的路径无法更改,也没有接口去获取此路径)
- 可以从远程服务器加载Object,也可以从本地存储加载Object。可以通过
file://
URL从本地存储加载文件。 - 每次下载时候,都会创建一个线程,每个线程会在托管堆中缓存一份解压后的AssetBundle,这可能导致内存飙升。
- 如果本地没有缓存,使用WWW网络下载文件。从网络下载的AssetBundle如果没有压缩,通过固定大小的缓冲区直接并写入本地缓存,如果有压缩还需要在固定大小的缓冲区中解压缩后,才能写入本地缓存。但是WWW对象将在托管堆中保留解压缩后的AssetBundle字节的完整副本。保留AssetBundle的额外副本以支持www.bytes等属性。一旦解压缩后的AssetBundle被缓存到本地,LoadFromCacheOrDownload将从本地缓存的解压缩AssetBundle加载数据头。
- 如果本地已有缓存,调用LoadFromCacheOrDownload,和调用LoadFromFile一样,由于本地缓存中是未压缩的AssetBundle,因此只会加载AssetBundle数据头。
public class LoadFromCacheOrDownloadExample : MonoBehaviour
{
IEnumerator Start()
{
while (!Caching.ready)
yield return null;
using (var www =
WWW.LoadFromCacheOrDownload("http://myserver.com/myassetBundle.unity3d", 5))
{
yield return www;
if (!string.IsNullOrEmpty(www.error))
{
Debug.Log(www.error);
yield return null;
}
var myLoadedAssetBundle = www.assetBundle;
var asset = myLoadedAssetBundle.mainAsset;
}
}
}
1.2 WWW (异步-无缓存机制)
WWW是一个Unity封装的网络下载模块,支持Http以及file两种URL协议。
直接使用LoadFromCacheOrDownload和WWW不同的是,读取不会再走WWW这一套。 WWW进行读取或者下载时候,都会创建一个线程,托管堆中缓存一份下载后的AssetBundle,同时开启多个下载,这可能导致内存飙升。使用WWW.Dispose将终止仍在加载过程中的进程,并释放掉托管堆中的AssetBundle。
通过www下载资源,然后释放托管堆内存。代码如下:
/// <summary>
///从服务器下载到本地
/// </summary>
/// <param name="AssetsHost">服务器路径</param>
/// <param name="AssetName">请求资源名称</param>
/// <param name="saveLocalPath">保存到本地路径,一般存在Application.persistentDataPath</param>
/// <returns></returns>
IEnumerator DownLoadAssetsWithDependencies2Local(string AssetsHost, string AssetName, string saveLocalPath)
{
WWW tempWwwAsset = new WWW(AssetsHost + "/" + AssetName);
//获取加载进度
yield return tempWwwAsset;
//直接读取AssetBundle
AssetBundle temp = tempWwwAsset.assetBundle;
//保存到本地
Stream tempStream = null;
FileInfo fileInfo = new FileInfo(saveLocalPath + "/" + AssetName);
if (fileInfo.Exists)
{
fileInfo.Delete();
}
//如果此文件不存在则创建
tempStream = fileInfo.Create();
//写入
tempStream.Write(tempWwwAsset.bytes, 0, tempWwwAsset.bytes.Length);
tempStream.Flush();
//关闭流
tempStream.Close();
//销毁流
tempStream.Dispose();
Debug.Log(name + "成功保存到本地~");
}