Unity3D教程:制作與載入AssetBundle


通常我們在游戲程式執行過程,並不希望一次將全部的資源都載入,而比較希望實際上有使用到的才載入,以免占用多余的記憶體,所以我們可能會盡量規划好不同功能的場景,在需要時才載入場景並釋放掉前個場景中不需要的資源,或是將資源放在 Resource 資料夾中,在真正需要時才利用 Resources.Load() 把資源載入;這些都是不錯的管理方法,但是當我們游戲中的資源相當多時,輸出的程式還是會相當龐大,而且如果是時常會更新內容資源的游戲,也會因為龐大的資源而造成編譯輸出時要花相當多的時間;特別是手機或網頁游戲,幾乎輸出最後的結果只是一個檔案而已,這個檔案如果很龐大,將可能造成下載或啟動游戲的不方便;這時候我們可能就要考慮制作 AssetBundle。

制作與游戲主程式分離的資源包可以得到某程度上的好處,我們可以讓游戲主程式只管理游戲邏輯的部份,當有需要某些資源則從外部的 AssetBundle 載入資源,這樣一來,如果有任何游戲更新只是添加或更換資源,並沒有變更到游戲程式邏輯或內容部署,我們只需要重新打包資源的部份就能完成更新,而不再需要整個游戲重新編譯輸出。

例如我們有已上架的 iPhone 游戲,因為特定節日想把游戲內的圖片換成另一種氣氛,通常就必須要重新輸出,然後送審,等節日過後又想把圖片換回原本的,要再次輸出游戲,再送審,一方面送審費時費工,另一方面是從送審到架上游戲更新完成的時間,我們並不能准確掌控;如果事先將資源分離打包成 AssetBundle 儲存在我們自己管理的伺服器中,在這種需要換圖的時刻,只需要打包自行在伺服器中將 AssetBundle 更新即可,可以省掉不斷送審的麻煩,時間上也更能掌控,另外就是游戲主程式中沒有龐大的資源資料,主程式也就會小一點,那麽玩家要下載我們的游戲也會更快速些。

還有就是,我們輸出為網頁游戲時一定會發現到,輸出結果只是一個 html 檔及一個 unity3d 檔,應該有寫過網頁的人都知道,網頁的運作是瀏覽器將網頁中的文件、圖片、音樂、影像… 等等的資料下載到客戶端暫存之後再執行呈現出結果,那麽如果我們游戲內容的龐大資源都與主程式編在一起的話,那麽輸出後的 unity3d 檔應該也會不小,此時我們可能要思考一下,我們希望玩家花多久時間完成啟動頁面再進行游戲呢?也許 Unity 的 Web Player 有辦法解決這個問題使玩家不會花太多時間啟動頁面,但是正因為網頁的運作方式是如此,所以當我們在伺服器端更新時,玩家只要沒有重新載入頁面,玩到的游戲內容始終是舊版的,此時又要考慮到,如果沒有更新游戲邏輯或內容規則的情況下,是否有必要強制玩家中斷游戲重新載入頁面;如果將資源都打包成 AssetBundle 分離出來,那麽 unity3d 檔這個主程式的部份將會變得更小,而當有任何資源更新時只需要在伺服器端將 AssetBundle 的檔案換掉,玩家不需要重新載入頁面一樣能體驗到更新後的內容。

以上主要說明 AssetBundle 是個很重要又好用的東西,畢竟在沒變更程式或游戲部署的情況下,沒必要去重新 Build 游戲主程式,以下就來說明如何制作 AssetBundle …

首先要自定義選單命令,使我們能夠操作何時開始制作 AssetBundle 及如何做,接下來我們需要能夠指定哪些資源將打包成 AssetBundle,所以需要使用到 Editor class 的 Selection.GetFiltered(),還有就是要過濾哪些型別的資源才是我們要的,選擇錯誤則略過,不要處理,最後再使用 BuildPipeline.BuildAssetBundle() 建立 AssetBundle 即可,以下范例會在 Unity 專案資料夾(不是 Asset 資料夾)中建立 _AssetBunldes 資料夾用來存放打包好的 AssetBundle,打包的目標為 GameObject、Texture2D、Material 三種型別的資源,如果儲存檔案路徑檔名相同則會先刪除舊檔:

  	 		
[MenuItem("Custom Editor/Create AssetBunldes")]
	
static void ExecCreateAssetBunldes(){
		
// AssetBundle 的資料夾名稱及副檔名	
string targetDir = "_AssetBunldes";	
string extensionName = ".assetBunldes";	
 
//取得在 Project 視窗中選擇的資源(包含資料夾的子目錄中的資源)	
Object[] SelectedAsset = Selection.GetFiltered(typeof (Object), SelectionMode.DeepAssets);	
 	
//建立存放 AssetBundle 的資料夾	
if(!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir);	
foreach(Object obj in SelectedAsset){	
//資源檔案路徑	
string sourcePath = AssetDatabase.GetAssetPath(obj);	
// AssetBundle 儲存檔案路徑	
string targetPath = targetDir + Path.DirectorySeparatorChar + obj.name + extensionName;	
if(File.Exists(targetPath)) File.Delete(targetPath);	
if(!(obj is GameObject) && !(obj is Texture2D) && !(obj is Material)) continue;	
//建立 AssetBundle
if(BuildPipeline.BuildAssetBundle(obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies)){	
Debug.Log(obj.name + " 建立完成");	
}else{	
Debug.Log(obj.name + " 建立失敗");	
}	
}	
}
以上是直接將選擇的資源打包成 AssetBundle,另外,你也可以在打包前依需求將型別為 GameObject 的資源 Instantiate 到場景中添加需要的 Component 並回到 Project 中建立 Prefab,最後再以這個 Prefab 打包成 AssetBundle,一切就看個人如何運用了。

制作好的 AssetBundle 最終目的還是要在游戲中載入,以下用簡短的范例在游戲畫面上顯示一個按鈕,當按下按鈕之后載入型別為 GameObject 的 AssetBundle 並利用 Instantiate() 使其實例化而在場景中產生 GameObject:

  	 		
void OnGUI(){	
if(GUI.Button(new Rect(5,35,100,25) , "Load GameObject")){	
StartCoroutine(LoadGameObject());	
}	
}
	
private IEnumerator LoadGameObject(){	
// AssetBundle 檔案路徑	
string path = string.Format("file://{0}/../_AssetBunldes/{1}.assetBunldes" , Application.dataPath , "TestGameObject");	
//  載入 AssetBundle	
WWW bundle = new WWW(path);	
//等待載入完成	
yield return bundle;
	
//實例化 GameObject 並等待實作完成	
yield return Instantiate(bundle.assetBundle.mainAsset);
	
//卸載 AssetBundle	
bundle.assetBundle.Unload(false);
}
范例中的檔案路徑(path)字串是以此程式碼在 Unity 編輯器中執行為例,實作時應該以實際執行平台及個人喜好指定 AssetBundle 存放路徑,詳情可參考官方文件 Application.dataPath 說明;因為載入的資源必須要等待載入完成以確保游戲運作正常,在 C# 使用 yield 除了回傳型別為 IEnumerator 之外,調用時也必須使用 StartCoroutine() 調用,如果使用 Javascript 則可直接呼叫該 function;如果 AssetBundle 已載入過,下次再請求載入將會出現 [The asset bundle ‘檔名' can't be loaded because another asset bundle with the same files are already loaded]的錯誤訊息,即使使用區域變數(范例中的 bundle)仍然會得到這個錯誤訊息,所以必須在每次載入使用完后將 AssetBundle 卸載;另外,要特別注意的是載入 AssetBundle 到卸載期間可能消耗些微時間,如果連續調用載入同一個 AssetBundle,造成在卸載前重復載入也可能出現前面的錯誤訊息,所以,最好是能定義個陣列或其它變數來記錄載入中的 AssetBundle 有哪些,以此變數內容在載入 AssetBundle 前檢查。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM