一、簡介
馬三在公司大部分時間做的都是游戲業務邏輯和編輯器工具等相關工作,因此對Unity AssetBundle這塊的知識點並不是很熟悉,自己也是有打算想了解並熟悉一下AssetBundle,掌握一下Unity資源管理方面的知識,因此有了這篇博客。
我會在博客中整理出一些自己學習時收集到的一些比較好的AssetBundle學習資料,並且結合現在正在參與開發的商業項目隨時寫下一些自己的拙見。本篇博客權當是馬三自己的筆記和一些雜談,會不斷地隨時隨地的更新一些內容。
二、收集整理的一些AssetBundle資料
1.Unity AssetBundle5講系列
Unity5-ABSystem(一):AssetBundle原理
Unity5-ABSystem(二):AssetBundle導出
Unity5-ABSystem(三):AssetBundle加載
Unity5-ABSystem(四):AssetBundle依賴
Unity5-ABSystem(五):AssetBundle內存
2.慕容小匹夫系列
Unity3D 5.3 新版AssetBundle使用方案及策略
3.何三思譯Unity AssetBundle官方文檔系列
【Unity3D技術文檔翻譯】第1.0篇 AssetBundles
【Unity3D技術文檔翻譯】第1.1篇 AssetBundle 工作流
【Unity3D技術文檔翻譯】第1.2篇 為打包 AssetBundles 准備資產
【Unity3D技術文檔翻譯】第1.3篇 創建 AssetBundles
【Unity3D技術文檔翻譯】第1.4篇 AssetBundle 依賴關系
【Unity3D技術文檔翻譯】第1.5篇 本地使用 AssetBundles
【Unity3D技術文檔翻譯】第1.6篇 使用 AssetBundle Manager
【Unity3D技術文檔翻譯】第1.7篇 AssetBundles 補丁更新
【Unity3D技術文檔翻譯】第1.8篇 AssetBundles 問題及解決方法
【Unity3D技術文檔翻譯】第1.9篇 使用 Unity AssetBundle Browser tool (AssetBundle系列完結)
4.Unity AssetBundle官方文檔
A guide to AssetBundles and Resources
5.Unity Assetbundles官方說明系列
Unity5.4 Assetbundles官方說明一(AssetBundles打包詳解)
Unity5.4 Assetbundles官方說明二(AssetBundle壓縮與解壓)
Unity5.4 Assetbundles官方說明三(AssetBundle資源包的內部結構)
Unity5.4 Assetbundles官方說明四(AssetBundles的下載和加載)
Unity5.4 Assetbundles官方說明五(從AssetBundles的加載和卸載資源對象)
Unity5.4 Assetbundles官方說明六(保留下載的AssetBundle)
Unity5.4 Assetbundles官方說明七(在AssetBundle中存儲和加載二進制數據)
Unity5.4 Assetbundles官方說明八(數據安全方面的處理)
Unity5.4 Assetbundles官方說明九(資源包中包含腳本文件)
Unity5.4 Assetbundles官方說明十(官方疑難問題解答)
Unity5.4 Assetbundles十一:遇到的坑和整理的打包和加載流程(資源包更新的簡易框架)
6.未規划分類
Unity AssetBundle 從入門到掌握(適合初學者)
Unity資源處理機制(Assets/WWW/AssetBundle/...)讀取和加載資源方式詳解
Unity3D中實現按資源名稱自動化命名打包AssetBundle
Unity AssetBundle加載音頻,無法播放音效並報錯的坑
Unity打包AssetBundle自動分析資源依賴關系(包括UGUI圖集打包)
7.AssetBundle分組策略總結
邏輯實體分組
一個UI界面或者所有UI界面一個包(這個界面里面的貼圖和布局信息一個包)
一個角色或者所有角色一個包(這個角色里面的模型和動畫一個包)
所有的場景所共享的部分一個包(包括貼圖和模型)
按照類型分組
所有聲音資源打成一個包,所有shader打成一個包,所有模型打成一個包,所有材質打成一個包
按照使用分組
把在某一時間內使用的所有資源打成一個包。可以按照關卡分,一個關卡所需要的所有資源包括角色、貼圖、聲音等打成一個包。也可以按照場景分,一個場景所需要的資源一個包
注意
經常更新的資源放在一個單獨的包里面,跟不經常更新的包分離
把需要同時加載的資源放在一個包里面
可以把其他包共享的資源放在一個單獨的包里面
把一些需要同時加載的小資源打包成一個包
如果對於一個同一個資源有兩個版本,可以考慮通過后綴來區分,例如v1、v2、v3
三、AssetBundle踩坑與經驗集錦
1、先說一個遇到的坑,當大量(幾百個)AssetBundle加載的時候(可能是WWW加載的時候,也可能是AssetBundle.LoadAsset的時候),Android手機上會閃退。看崩潰log是多線程文件訪問的時候崩潰了。解決方法是減少同時加載的AB數量(這個是純邏輯控制),使用AssetBundle.LoadFromFile接口。
2、打包AssetBundle使用LZ4壓縮(BuildPipeline.BuildAssetBundles,第二個參數傳遞BuildAssetBundleOptions.ChunkBasedCompression),默認是LZMA壓縮的,具有最高的壓縮比。而替換為LZ4壓縮,壓縮比沒有LZMA高,但是加載速度大幅提高。加載AssetBundle使用AssetBundle.LoadFromFile(Async),在Unity4的時候,只能使用WWW的接口來加載AB,因為CreateFromFile不支持壓縮的AB。而Unity5的LoadFromFile是支持任意壓縮格式的AB的。所以沒有太大必要使用WWW了,而且這個接口像WWW.LoadFromCacheOrDownload接口一樣,加載不壓縮或者LZ4壓縮格式的AB的時候是不會有額外的內存開銷的。具體關於內存、加載速度的細節可以參考上面第三篇文章里面的介紹。
3、資源規划好一個獨立的資源工程。規划好一系列的文件夾,在導入相應資源的時候自動通過AssetImporter設置好AB的名字。監測資源導入可以用AssetPostprocessor 。帶動畫的模型需要創建好prefab,而不帶動畫只是用於換裝的模型可以直接導出,不需要創建prefab,因為這些模型我們只是取它的mesh數據。如果有打包圖集,需要注意它和AB的匹配關系,舉例來說,如果三張圖片指定了同一個圖集,而又分別指定了不同的AB名,則三個AB里面都包含了此圖集(三張圖片),這樣就會造成嚴重的資源浪費。
4、AssetBundle.LoadFromFile接口在Android平台下也是可以直接訪問StreamingAssets文件夾里面的內容的。5.4版本可以直接使用Application.streamingAssetsPath。而之前的版本需要使用 Application.dataPath + "!assets/" + filePath; 因為streamingAssetsPath帶了jar://,這個是給WWW用的URL路徑,而LoadFromFile接口需要的是實際路徑(不帶jar://也不帶file://)。注意 !assets/ 這個地方嘆號后面沒有/。網上搜索到的各種寫法都有,只有這個是正確的,注意此處細節。
四、Unity AssetBundle爬坑手記
文章轉載自:http://www.cnblogs.com/ybgame/p/3973177.html
1 Object obj = AssetDatabase.LoadMainAssetAtPath("Assets/Test.png"); 2 BuildPipeline.BuildAssetBundle(obj, null, 3 Application.streamingAssetsPath + "/Test.assetbundle", 4 BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets 5 | BuildAssetBundleOptions.DeterministicAssetBundle, BuildTarget.StandaloneWindows);
在使用的時候,需要用WWW來加載Bundle,然后再用加載出來的Bundle來Load資源。
WWW w = new WWW("file://" + Application.streamingAssetsPath + "/Test.assetbundle"); myTexture = w.assetBundle.Load("Test");
Directory.GetFiles("Assets/MyDirs", "*.*", SearchOption.TopDirectoryOnly); Directory.GetDirectories(Application.dataPath + "/Resources/Game", "*.*", SearchOption.AllDirectories);
string newPath = "Assets" + mypath.Replace(Application.dataPath, ""); newPath = newPath.Replace("\\", "/"); Object obj = AssetDatabase.LoadMainAssetAtPath(newPath);
在打對應的包之前應該先選擇對應的平台再打包
string.Format("file://{0}/{1}", Application.streamingAssetsPath, bundlePath);
string.Format("jar:file://{0}!/assets/{1}", Application.dataPath, bundlePath);
IEnumerator LoadBundle(string url)
{
WWW www = = new WWW(url);
yield return www;
if (www.error != null)
{
Debug.LogError("Load Bundle Faile " + url + " Error Is " + www.error);
yield break;
}
//Do something ...
}
//將所有對象加載資源
Object[] objs = bundle.LoadAll();
//加載名為obj的資源
Object obj = bundle.Load("obj");
//異步加載名為resName,類型為type的資源
AssetBundleRequest res = bundle.LoadAsync(resName, type);
yield return res;
var obj = res.asset;
//需要先實例化
GameObject obj = GameObject.Instantiate(bundle.Load("MyPrefab")) as GameObject;
bundle.Load("MyPrefab", typeof(GameObject))
string path = Application.streamingAssetsPath;
BuildPipeline.PushAssetDependencies();
BuildTarget target = BuildTarget.StandaloneWindows;
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/UI_tck_icon_houtui.png"), null,
path + "/package1.assetbundle",
BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
| BuildAssetBundleOptions.DeterministicAssetBundle, target);
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/New Material.mat"), null,
path + "/package2.assetbundle",
BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
| BuildAssetBundleOptions.DeterministicAssetBundle, target);
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Cube.prefab"), null,
path + "/package3.assetbundle",
BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
| BuildAssetBundleOptions.DeterministicAssetBundle, BuildTarget.StandaloneWindows);
BuildPipeline.PopAssetDependencies();
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Cubes.prefab"), null,
path + "/package4.assetbundle",
BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets
| BuildAssetBundleOptions.DeterministicAssetBundle, target);
BuildPipeline.PopAssetDependencies();
BuildPipeline.PopAssetDependencies();
[Serializable]
public class ResConfigData
{
public string ResName; //資源名字
public string BundleName; //包名字
public string Path; //資源路徑
public int Vesrion; //版本號
}
[System.Serializable]
public class ResConfig : ScriptableObject
{
public List<ResConfigData> ConfigDatas = new List<ResConfigData>();
}
ResConfig obj = (ResConfig)AssetDatabase.LoadAssetAtPath(path, typeof(ResConfig));
if (obj == null)
{
obj = ScriptableObject.CreateInstance<ResConfig>();
AssetDatabase.CreateAsset(obj, path);
}
EditorUtility.SetDirty(obj);

