Unity5.x新依賴打包及載入
寫在前面:
很久很久很久。。沒有更新了,當然寫這個需要堅持,最近因為工作調整轉了移動開發,之後的部落格更新會以移動開發為主了,當然寫部落格純粹是為了記錄自己的學習過程,畢竟好記性不如硬鍵盤嘛,有什麼錯誤的地方還望大家指正。
Unity自5.0開始提供了新的AssetBundle打包Api,以下是新舊Api對比:
舊版:
圖1
打包方式:
public class ExportAssetBundles {
[MenuItem("Assets/Build AssetBundle From Selection - Track dependencies")]
static void ExportResource () {
// Bring up save panel
string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d");
if (path.Length != 0) {
// Build the resource file from the active selection.
Object[] selection = Selection.GetFiltered(typeof (Object), SelectionMode.DeepAssets);
BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, 0);
Selection.objects = selection;
}
}
[MenuItem("Assets/Build AssetBundle From Selection - No dependency tracking")]
static void ExportResourceNoTrack () {
// Bring up save panel
string path = EditorUtility.SaveFilePanel ("Save Resource", "", "New Resource", "unity3d");
if (path.Length != 0) {
// Build the resource file from the active selection.
BuildPipeline.BuildAssetBundle(Selection.activeObject, Selection.objects, path);
}
}
}
而在目前最新的Unity2017版本中,舊版本的打包方式已經被完全廢棄了。
新版打包Api:
圖2
public class PackageAssetBundle : MonoBehaviour {
[MenuItem("Build/Build AssetBundles")]
static void buildAssetBundles()
{
string buildPath = Application.dataPath + "/Assets/Abs";//打包路徑
if (!Directory.Exists(buildPath))
Directory.CreateDirectory(buildPath);
BuildPipeline.BuildAssetBundles(buildPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
}
}
可以看到打包的程式碼非常簡單。
如何指定需要打包的assets?
有幾種方式:
第一種是直接在Inspecot面板進行指定:
圖3
打包時Api將選擇所有你指定了AssetBundle VarName的資源,然後統一進行打包,如圖3中該資源被打包後最終會生成cube.ab和cube.ab.manifest兩個檔案,manifest檔案中記錄的是cube.ab的資訊,如依賴資源等等。
第二種呢是在程式碼中進行指定:
public class BuildAssetBundlesBuildMapExample : MonoBehaviour
{
[MenuItem("Example/Build Asset Bundles Using BuildMap")]
static void BuildMapABs()
{
// Create the array of bundle build details.
AssetBundleBuild[] buildMap = new AssetBundleBuild[2];
buildMap[0].assetBundleName = "enemybundle";
string[] enemyAssets = new string[2];
enemyAssets[0] = "Assets/Textures/char_enemy_alienShip.jpg";
enemyAssets[1] = "Assets/Textures/char_enemy_alienShip-damaged.jpg";
buildMap[0].assetNames = enemyAssets;
buildMap[1].assetBundleName = "herobundle";
string[] heroAssets = new string[1];
heroAssets[0] = "char_hero_beanMan";
buildMap[1].assetNames = heroAssets;
BuildPipeline.BuildAssetBundles("Assets/ABs", buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
}
}
當然指定方式靈活度還是不錯的,你可以直接Selection,然後再對Selection的資源構造成buildMap,再進行處理即可。
打包說完了,接著就是載入咯。
如何載入?
載入可以分為三個步驟:
1.首先讀取Manifest檔案,讀取需要載入ab(AssetBundle)的依賴資源
2.載入依賴ab
3.載入ab
ok,說了這麼多好像。。。
那好吧,接下來還是看個小例子吧.
打包資源如下:
圖4
依賴關係:
Prefabs | depends | Materials |
---|---|---|
cube.ab | depend on | texure.ab |
capsule.ab | depend on | emission.ab |
我們只需要把材質掛在prefabs上即可,Unity新的打包方式會自動幫我們處理依賴關係的,執行打包程式碼後得到如下目錄:
圖5
show in explorer來看看:
圖6
如圖6所示,打包完成後,在打包路徑下生成了一個和當前路徑資料夾同名的AssetBundle檔案和一個manifest檔案,這兩個檔案是有用的,別隨便刪除了哈。。。
但是改個名字什麼的還是可以的哈。
接著來看一下檔案大小,畢竟我們使用依賴打包的目的是為了減小包的大小不是嘛:
ab | size |
---|---|
cube.ab | 1.72KB |
capsule.ab | 1.78KB |
texure.ab | 147KB |
emission.ab | 510KB |
哎,沒錯的吧,cube和capsule中確實剔除了材質,大小隻有一點多KB,來看一下依賴資訊,就是它:
圖7
我們可以發現裡面清晰的記錄每個ab的依賴資源資訊。
載入方式
AssetBundle的載入方式有好幾種,這裡介紹兩種常用的:
1.LoadFromFile:
public GameObject loadAssetBundleFiles(string filePath, string manifestBundleName, string abFileName, string prefabFileName)
{
/**
* 1.首先從打包路徑獲取依賴
* 這裡載入的就是生成的同名檔案ab,這裡應該是filePath/Abs,當然會這個名稱也可以修改
*/
AssetBundle manifestBundle = AssetBundle.LoadFromFile(getManifestFilePath(filePath, manifestBundleName));
/**
* 2.獲取依賴資源列表
*/
if (manifestBundle != null)
{
try
{
AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");//固定載入方式,通過 assetbundle Abs載入Abs.manifest
manifestBundle.Unload(false);
//獲取載入ab的依賴資訊,引數為ab名稱,如cube.ab
string[] dependsFile = manifest.GetAllDependencies(abFileName);
if (dependsFile.Length > 0)
{
//根據獲取到的依賴資訊載入所有依賴資源ab
AssetBundle[] dependsBundle = new AssetBundle[dependsFile.Length];
for (int i = 0; i < dependsFile.Length; i++)
{
String fp = generateAbsoluteFile(filePath, dependsFile[i]);
Debug.Log(String.Format("depends:{0}:{1}", i, dependsFile[i]));
dependsBundle[i] = AssetBundle.LoadFromFile(fp);
}
}
}
catch (InvalidCastException e)
{
Debug.LogException(e);
}
/**
* 3.最後載入ab
* 注意這裡的LoadAsset的引數是Prefab的名稱,無後綴,如cube而非cube.ab或cube.prefab
*/
AssetBundle ab = AssetBundle.LoadFromFile(generateAbsoluteFile(filePath, abFileName));
GameObject go = ab.LoadAsset(prefabFileName) as GameObject;
ab.Unload(false);
return go;
}
return null;
}
2.WWW載入:
IEnumerator wwwGetAssetBundles(string filePath, string manifestName, string abFileName, string prefabFileName)
{
//WWW www = WWW.LoadFromCacheOrDownload(getManifestFilePath(filePath), 0);
WWW www = new WWW(manifestName);
yield return www;
if (!string.IsNullOrEmpty(www.error))
{
Debug.LogError(www.error);
}
else
{
/**
* 1.首先從打包路徑獲取依賴
*/
AssetBundle manifestBundle = www.assetBundle;
/**
* 2.獲取依賴資源列表
*/
if (manifestBundle != null)
{
AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
manifestBundle.Unload(false);
www.Dispose();
string[] dependsFile = manifest.GetAllDependencies(abFileName);
if (dependsFile.Length > 0)
{
AssetBundle[] dependsBundle = new AssetBundle[dependsFile.Length];
for (int i = 0; i < dependsFile.Length; i++)
{
String fp = generateAbsoluteFile(filePath, dependsFile[i]);
Debug.Log(String.Format("depends:{0}:{1}", i, dependsFile[i]));
www = new WWW(fp);
yield return www;
if(www.error == null)
{
dependsBundle[i] = www.assetBundle;
www.Dispose();
}
}
}
/**
* 3.最後載入ab
*/
AssetBundle ab = AssetBundle.LoadFromFile(generateAbsoluteFile(filePath, abFileName));
GameObject go = ab.LoadAsset(prefabFileName) as GameObject;
if (go != null)
{
GameObject.Instantiate(go);
}
ab.Unload(false);
}
}
}
程式碼和第一種載入方式大致相同。
最後說一點使用時需要注意的地方,舉個例子,比如說我們有一公用的資源,A、B、C三個ab都需要依賴D,那麼在程式中我們需要載入A時會先載入D,然後載入A,這個時候B也需要被載入了,因為程式不知道D已經被載入了,所以再次去讀取依賴資訊,嘗試載入D,這樣就會消耗一些cpu的時間了,因此在我們實際開發中應該更加合理的去管理公用的ab資源,對於不常用的公用ab使用過後及時解除安裝,下次使用再進行載入,而對用經常使用需要常駐記憶體的ab資源,最好在程式中設定一個標識,標記其是否已經被載入,存在於記憶體中,然後在載入依賴該公用ab的ab資源時判斷該公用ab是否已被載入,當然,也可能會存在一個ab依賴多個公用資源,這種情況就需要開發者更加謹慎的去處理依賴關係了,最好建立統一的管理,做到邏輯清晰。
Over:最後貼出
官網連結:BuildAssetBundles
Demo下載連結(Unity5.x):Demo地址
密碼:m4q2