一、AssetBundle理解
1、AssetBundle介绍
Unity引擎的AssetBundle本质是一种资源管理技术,通过动态的加载与卸载资源,极大的节约游戏所占空间,而且这种技术也实现了游戏发布后关于资源的后续跟新与完善,所以这也是一种游戏的实时热更新技术。
AssetBundle是一个压缩包。它包含模型、贴图、预制体、音频等资源,也可以在游戏运行期被加载。
(Unity5.x之后)AssetBundle自身保存着互相依赖关系。压缩包可以使用LZMA和LZ4压缩算法,减少包大小,更快的进行网络传输。具体到商业游戏中,可以把游戏后期运行的大量资源都放到AssetBundle里面,可以大幅减少安装包尺寸。
2、AssetBundle使用过程
总体来说AssetBundle可以分为以下四个部分
(1) 创建AssetBundle
(2)上传资源服务器
(3)下载AssetBundle资源
(4)加载与卸载AssetBundle资源。
二、AssetBundle具体使用
早期基于Unity4.x版本期间,创建AssetBundle是一件需要些大量代码且类容易出错的事情,但到了Unity5.x以后这一过程已经大大简化。
基于Unity2017版本创建AssetBundle可以为以下3大步骤
(1)打AB包
1、首先定位需要打包与加载的资源,资源可以是任意类型(如:贴图、材质、音频、预设等)。在项目视图中选中资源,属性窗口下方可以看到资源预览。在AssetBundle后面输入需要打包的"AssetBundle名称"。
2、编写打包脚本(BuildAssetBundle.cs)在编写的前确认脚本定义在"Editor"的特殊文件加下
3、打包核心API:
BuildPipeline.BuildAssetBundles("AB输出路径",BuildAssetBundleOptions.None,BuildTarget.StandaloneWindows64);
4、编写脚本,在Unity编辑器顶部菜单会出现自定义的AB菜单。点击菜单后开始打包,大约几秒钟后在项目视图的StreamingAssets目录下我们可以看到打包好的文件资源。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
public class BuildAssetBundle
{
[MenuItem("AssetBundleTools/BuildAllAssetBundles")]
public static void BuildAllAB()
{
//打包AB输出路径
string strABOutPathDIR = string.Empty;
strABOutPathDIR = Application.streamingAssetsPath;
//判断生成输出目录 如果不存在 //创建目录
if (!Directory.Exists(strABOutPathDIR)) Directory.CreateDirectory(strABOutPathDIR);
//打包生成
BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
}
}
(2) 下载AssetBundle
Unity目前提供了两种通过www类下载AssetBundle文件的方法。
第一种是"缓存机制"。 采用这种机制下载的AssetBundle文件会存入Unity引擎的缓存区,通过www类的静态方法LoadFromCacheOrDownload实现下载。
第二种是"非缓存机制"。采用这种机制下载的AssetBundle文件不会存入Unity引擎的缓存区.。(www.assetBundle)
通过www类的实例方法www.assetBundle实现下载源码
1、加载非 "对象预设"方式(例如:贴图、材质、音频...)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
AssetBundle基本加载
* 1、加载非 "对象预设"方式(例如:贴图、材质、音频...)
2、加载预制体
*/
public class AssetBundleLoadDemo : MonoBehaviour
{
//测试对象,改变贴图
public GameObject goCubeChangeTexture;
//定义URL
private string _URL1;
private string _AssetName1;
void Start()
{
_URL1 = "file://" + Application.streamingAssetsPath + "/texture1";
_AssetName1 = "t1";
StartCoroutine(LoadNonObjectFromAB(_URL1, goCubeChangeTexture, _AssetName1));
}
/// <summary>
/// 加载"非GameObject"资源
/// </summary>
/// <param name="ABURL">ABURL </param>
/// <param name="goShowObj"></param>
/// <param name="assetName"></param>
/// <returns></returns>
IEnumerator LoadNonObjectFromAB(string ABURL, GameObject goShowObj, string assetName)
{
// 参数检查
if (string.IsNullOrEmpty(ABURL) || goShowObj == null) Debug.LogError(GetType() + "/LoadNonObjectFromAB()/输入的参数不合法请检查");
using (WWW www = new WWW(ABURL))
{
yield return www;
AssetBundle ab = www.assetBundle;
if (ab != null)
{
//加载资源
if (assetName == "")
{
goShowObj.GetComponent<Renderer>().material.mainTexture=(Texture)ab.mainAsset;
}
else
{
goShowObj.GetComponent<Renderer>().material.mainTexture = (Texture)ab.LoadAsset(assetName);
}
//卸载资源(只卸载AB包本身)
ab.Unload(false);
}
else Debug.LogError(GetType() + "/LoadNonObjectFromAB()/www 下载错误,请检查 URL:" + ABURL + "错误信息" + www.error);
}
}
}
2、加载"对象预设"(*。Prefab)方式.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
AssetBundle基本加载
* 1、加载非 "对象预设"方式(例如:贴图、材质、音频...)
* 2、加载"对象预设"(*。Prefab)方式.
*/
public class AssetBundleLoadDemo : MonoBehaviour
{
//测试对象,改变贴图
//public GameObject goCubeChangeTexture;
//定义URL
private string _URL1;
private string _AssetName1;
private string _URL2;
private string _AssetName2;
public Transform cu;
void Start()
{
//_URL1 = "file://" + Application.streamingAssetsPath + "/texture1";
//_AssetName1 = "t1";
//StartCoroutine(LoadNonObjectFromAB(_URL1, goCubeChangeTexture, _AssetName1));
_URL2 = "file://" + Application.streamingAssetsPath + "/pre";
_AssetName2 = "Cube";
StartCoroutine(LoadPrefabsFromAB(_URL2, _AssetName2, cu));
}
/// <summary>
/// 加载"非GameObject"资源
/// </summary>
/// <param name="ABURL">ABURL </param>
/// <param name="goShowObj">用于展示贴图的物体</param>
/// <param name="assetName">贴图名称</param>
/// <returns></returns>
IEnumerator LoadNonObjectFromAB(string ABURL, GameObject goShowObj, string assetName)
{
// 参数检查
if (string.IsNullOrEmpty(ABURL) || goShowObj == null) Debug.LogError(GetType() + "/LoadNonObjectFromAB()/输入的参数不合法请检查");
using (WWW www = new WWW(ABURL))
{
yield return www;
AssetBundle ab = www.assetBundle;
if (ab != null)
{
//加载资源
if (assetName == "")
{
goShowObj.GetComponent<Renderer>().material.mainTexture=(Texture)ab.mainAsset;
}
else
{
goShowObj.GetComponent<Renderer>().material.mainTexture = (Texture)ab.LoadAsset(assetName);
}
//卸载资源(只卸载AB包本身)
ab.Unload(false);
}
else Debug.LogError(GetType() + "/LoadNonObjectFromAB()/www 下载错误,请检查 URL:" + ABURL + "错误信息" + www.error);
}
}
/// <summary>
/// 加载一个预制体
/// </summary>
/// <param name="ABURL">AB包路径</param>
/// <param name="assetName">预设名字</param>
/// <param name="showPosition">预设要放置的位置</param>
/// <returns></returns>
IEnumerator LoadPrefabsFromAB(string ABURL,string assetName,Transform showPosition=null)
{
//检查参数
if (string.IsNullOrEmpty(ABURL)) Debug.LogError(GetType() + "/LoadPrefabsFromAB() 输入的参数不合法 请检查");
using(WWW www = new WWW(ABURL))
{
yield return www;
AssetBundle ab = www.assetBundle;//通过www下载ab包
//加载ab包
if (ab != null)
{
if (assetName == null)
{
//加载主资源
if (showPosition != null)
{
GameObject goCloneObj = Instantiate(ab.mainAsset) as GameObject;
goCloneObj.transform.position = showPosition.position;
}
else
{
Instantiate(ab.mainAsset);
}
}
else
{
//实例化指定资源
if (showPosition != null)
{
GameObject goCloneObj = Instantiate(ab.LoadAsset<GameObject>(assetName)) as GameObject;
goCloneObj.transform.position = showPosition.position;
Debug.Log("2222");
}
else
{
Instantiate(ab.LoadAsset<GameObject>(assetName));
Debug.Log("33333");
}
}
}
else Debug.LogError(GetType() + "/LoadPrefabsFromAB()/www下载错误 请检查 ARURL:"+ABURL+"错误信息"+www.error);
//卸载ab包
ab.Unload(false);
}
//加载ab包
}
}
三、AssetBundle原理讲解
1、在应用AssetBundle资源前,AssetBundle首先需要通过WWW下载到本地,然后AssetBundle在Unity引擎帮助下自动解压缩,这一过程也称为“内存镜像”
2、然后需要加载AssetBundle到内存区域中通过相关操作,最终创建具体的游戏对象才能显示与应用。
3、AssetBundel加载常用API
1、Unity2017提供了三种不同的方法来加载已经下载的数据资源。
2、assetBundle.LoadAsset();通过指定assetBundle包名称加载资源。
3、assetBundle.LoadAssetAsync();异步加载模式。与上述类似,但是加载过程不会同时阻碍主线程的运行,这特别适合需要读取大尺寸资源,以及一次性读取多个资源的场合。
4、assetBundle.LoadAllAssets();加载assetBundle中包含的所有资源对象。
4、AssetBundle依赖关系
Untiy4.x 之前老版本的AssetBundle系统需要自己写很多代码(BuildPipeline),从而增加了很多学习成本。正确处理好资源的依赖关系从而保证资源完整而又不会产生重复资源,是一件比较麻烦的事情。
从Unity5.x开始之后的新的AssetBundle大大简化了这一操作。Unity打包的时候会自动处理依赖关系,并生成一个*.manifest文件,这个文件描述了assetbundle包大小、CRC验证、包之间的依赖关系等。