Unity3D關於AssetBundle框架設計(A)
阿新 • • 發佈:2018-12-09
一、思路如下:
①開發專門的標記指令碼,自動給指定目錄下面的所有合法資原始檔(預設、貼圖、材質等)新增標記。
②通過寫專門的指令碼讀取Unity自動建立的 *.manifest檔案;自動分析和維護AssetBundle包之間的依賴關係,使得包的依賴關係可以實現迴圈依賴和自動化載入。
③開發針對AssetBundle專門框架,按照一定的嚴格流程解決AB包載入、複雜依賴、資源提取釋放等事宜,儘可能讓最終使用的框架人員只關心輸入和輸出結果部分,遮蔽內部的複雜性。
④開發的AssetBundle框架中,需要對AssetBundle包之間,以及AssetBundle包記憶體的資源做快取設計,並且提供引數開關,讓開發者自行決定是否應用快取載入。
二、AssetBundle框架總體分為三個部分
《1》自動化建立AssetBundle
《2》單一AssetBundle包的載入與管理
《3》AssetBundle整體管理
《1》自動化建立AssetBundle(以下三個指令碼需要放在Editor資料夾下面)
①自動給資原始檔新增標記(AutoSetLableToPrefabs.cs)
/*** * * Title: "AssetBundle工具包"專案 * (自動)給資原始檔(預設)新增標記 * * Description: * 開發思路: * 1:定位需要打包資源的資料夾根目錄。 * 2:遍歷每個“場景”資料夾(目錄) * 2.1> 遍歷本場景目錄下的所有的目錄或者檔案。 如果是目錄,則繼續遞迴訪問裡面的檔案,直到定位到檔案。 * 2.2> 找到檔案,修改AssetBundle 的標籤(label) * 具體用AssetImporter 類實現,修改包名與字尾。 * Date: 2018 * * Version: 1.0 * * Modify Recorder: * */ using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; namespace ABTools { public class AutoSetLabelToPrefabs { [MenuItem("AssetBundleTools/Set AB Label")] public static void SetABLabels(){ //需要給AB做標記的根目錄 string strNeedSetABLableRootDIR = string.Empty; //目錄資訊 DirectoryInfo[] dirScenesDIRArray = null; //清空無用AB標記 AssetDatabase.RemoveUnusedAssetBundleNames(); //定位需要打包資源的資料夾根目錄。 strNeedSetABLableRootDIR = PathTools.GetABResourcesPath(); DirectoryInfo dirTempInfo = new DirectoryInfo(strNeedSetABLableRootDIR); dirScenesDIRArray = dirTempInfo.GetDirectories(); //遍歷每個“場景”資料夾(目錄) foreach (DirectoryInfo currentDIR in dirScenesDIRArray){ //遍歷本場景目錄下的所有的目錄或者檔案, //如果是目錄,則繼續遞迴訪問裡面的檔案,直到定位到檔案。 string tmpScenesDIR = strNeedSetABLableRootDIR + "/" + currentDIR.Name; DirectoryInfo tmpScenesDIRInfo = new DirectoryInfo(tmpScenesDIR); //場景目錄資訊 int tmpIndex = tmpScenesDIR.LastIndexOf("/"); string tmpScenesName = tmpScenesDIR.Substring(tmpIndex+1); //場景名稱 //遞迴呼叫與處理目錄或檔案系統,如果找到檔案,修改AssetBundle 的標籤(label) JudgeDIROrFileByRecursive(currentDIR,tmpScenesName); }//foreach_end //重新整理 AssetDatabase.Refresh(); //提示 Debug.Log("AssetBundles 本次操作設定成功!"); } /// <summary> /// 遞迴呼叫與處理目錄或檔案系統 /// 1:如果是目錄,則進行遞迴呼叫。 /// 2:如果是檔案,則給檔案做“AB標記” /// </summary> /// <param name="dirInfo">目錄資訊</param> /// <param name="scenesName">場景名稱</param> private static void JudgeDIROrFileByRecursive(FileSystemInfo fileSysInfo,string scenesName){ if (!fileSysInfo.Exists) { Debug.LogError("檔案或目錄名稱: " + fileSysInfo.Name + " 不存在,請檢查!"); return; } //得到當前目錄下一級的檔案資訊集合 DirectoryInfo dirInfoObj = fileSysInfo as DirectoryInfo; FileSystemInfo[] fileSysArray = dirInfoObj.GetFileSystemInfos(); foreach (FileSystemInfo fileInfo in fileSysArray) { FileInfo fileInfoObj = fileInfo as FileInfo; //檔案型別 if (fileInfoObj!=null){ //修改此檔案的AssetBundle的標籤 SetFileABLabel(fileInfoObj, scenesName); } //目錄型別 else { //遞迴下一層 JudgeDIROrFileByRecursive(fileInfo, scenesName); } } } /// <summary> /// 修改檔案的AssetBundle 標記 /// </summary> /// <param name="fileInfo">檔案資訊</param> /// <param name="scenesName">場景名稱</param> private static void SetFileABLabel(FileInfo fileInfo,string scenesName){ //AssetBundle 包名稱 string strABName = string.Empty; //(資源)檔案路徑(相對路徑) string strAssetFilePath = string.Empty; //引數檢查 if (fileInfo.Extension == ".meta") return; //得到AB包名 strABName = GetABName(fileInfo, scenesName).ToLower(); /* 使用AssetImporter 類,修改名稱與字尾 */ //獲取資原始檔相對路徑 int tmpIndex = fileInfo.FullName.IndexOf("Assets"); strAssetFilePath = fileInfo.FullName.Substring(tmpIndex); //給資原始檔設定AB名稱與字尾 AssetImporter tmpAssetImportObj = AssetImporter.GetAtPath(strAssetFilePath); tmpAssetImportObj.assetBundleName = strABName; //設定AB包名 if (fileInfo.Extension==".unity") //設定AB包副檔名稱 tmpAssetImportObj.assetBundleVariant = "u3d"; else tmpAssetImportObj.assetBundleVariant = "ab";//AB資源包 } /// <summary> /// 獲取包名 /// </summary> /// <param name="fileInfo">檔案資訊</param> /// <param name="scenesName">場景名稱</param> /// <returns> /// 返回: 包名稱 /// </returns> private static string GetABName(FileInfo fileInfo,string scenesName) { string strABName = string.Empty; //Win路徑 string tmpWinPath = fileInfo.FullName; //Unity路徑 string tmpUnityPath = tmpWinPath.Replace("\\","/"); //定位“場景名稱”後面的字元位置 int tmpSceneNamePosIndex = tmpUnityPath.IndexOf(scenesName) + scenesName.Length; //AB檔名稱大體區域 string strABFileNameArea = tmpUnityPath.Substring(tmpSceneNamePosIndex + 1); if (strABFileNameArea.Contains("/")) { string[] tmpStrArray=strABFileNameArea.Split('/'); strABName = scenesName + "/" + tmpStrArray[0]; } else { strABName = scenesName+"/"+ scenesName; } return strABName; } }//Class_end }
②打包資源且輸出路徑(BuildAssetBundle.cs)
/*** * * Title: "AssetBundle工具包"專案 * 給AssetBundle目錄(資源)打包 * * Description: * 功能:[本指令碼的主要功能描述] * * Date: 2018 * * Version: 1.0 * * Modify Recorder: * */ using System.Collections; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; namespace ABTools { public class BuildAssetBundle { /// <summary> /// 打包生成所有AssetBundles /// </summary> [MenuItem("AssetBundleTools/BuildAllAssetBundles")] public static void BuildAllAB() { //(打包)AB的輸出路徑 string strABOutPathDIR = string.Empty; strABOutPathDIR = PathTools.GetABOutPath(); if (!Directory.Exists(strABOutPathDIR)) { Directory.CreateDirectory(strABOutPathDIR); } //打包生成 BuildPipeline.BuildAssetBundles(strABOutPathDIR,BuildAssetBundleOptions.None,BuildTarget.StandaloneWindows64); } }//Class_end }
③刪除路徑中的所有資源(DeleteAssetBundle.cs)
/***
*
* Title: "AssetBundle工具包"專案
* 刪除AssetBundle包檔案
*
* Description:
* 功能:[本指令碼的主要功能描述]
*
* Date: 2018
*
* Version: 1.0
*
* Modify Recorder:
*
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
namespace ABTools
{
public class DeleteAssetBundle
{
[MenuItem("AssetBundleTools/DeleteAllAssetBundles")]
public static void DeleteAllABs()
{
//(打包)AB的輸出路徑
string strNeedDeleteDIR = string.Empty;
strNeedDeleteDIR = PathTools.GetABOutPath();
if (!string.IsNullOrEmpty(strNeedDeleteDIR))
{
//引數true 表示可以刪除非空目錄。
Directory.Delete(strNeedDeleteDIR, true);
//去除刪除警告
File.Delete(strNeedDeleteDIR + ".meta");
//重新整理
AssetDatabase.Refresh();
}
}
}//Class_end
}
注意:涉及到路徑及其常量定義專門用一個Helps資料夾儲存
/***
*
* Title: "AssetBundle工具包"專案
* 專案常量、列舉、委託等定義
*
* Description:
* 注意:
* 不包含關於本專案路徑資訊,由其他幫助類單獨管理
*
* Date: 2018
*
* Version: 1.0
*
* Modify Recorder:
*
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABTools
{
/* 委託定義區 */
/// <summary>
/// AssetBundle 載入完成
/// </summary>
/// <param name="abName">AssetBundle 名稱</param>
public delegate void DelLoadComplete(string abName);
/* 列舉型別定義區 */
/* 本專案常量定義區 */
public class ABDefine
{
public static string ASSETBUNDLE_MANIFEST = "AssetBundleManifest";
}//Class_end
}
/***
*
* Title: "AssetBundle工具包"專案
* 路徑工具類
*
* Description:
* 功能:包含路徑方法、路徑常量
*
* Date: 2018
*
* Version: 1.0
*
* Modify Recorder:
*
*/
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace ABTools
{
public class PathTools
{
/* 路徑常量 */
public const string AB_RESOURCES = "AB_Res";//AB_Resources
/// <summary>
/// 獲取AB資源(輸入目錄)
/// </summary>
/// <returns></returns>
public static string GetABResourcesPath()
{
return Application.dataPath + "/"+ AB_RESOURCES;
}
/// <summary>
/// 獲取AB輸出路徑
/// 說明:
/// 由兩部分構成
/// 1: 平臺(PC/移動端)路徑。
/// 2: 平臺(PC/移動端)名稱
/// </summary>
/// <returns></returns>
public static string GetABOutPath()
{
return GetPlatformPath() + "/" + GetPlatformName();
}
/// <summary>
/// 獲取WWW協議路徑
/// </summary>
/// <returns></returns>
public static string GetWWWPath()
{
string strReturnWWWPath = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strReturnWWWPath = "file://"+GetABOutPath();
break;
case RuntimePlatform.Android:
strReturnWWWPath = "jar:file://" + GetABOutPath();
break;
default:
break;
}
return strReturnWWWPath;
}
/// <summary>
/// 獲取平臺路徑
/// </summary>
/// <returns></returns>
private static string GetPlatformPath()
{
string strReturnPlatformPath = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strReturnPlatformPath = Application.streamingAssetsPath;
break;
case RuntimePlatform.IPhonePlayer:
case RuntimePlatform.Android:
strReturnPlatformPath = Application.persistentDataPath;
break;
default:
break;
}
return strReturnPlatformPath;
}
/// <summary>
/// 獲取平臺名稱
/// </summary>
/// <returns></returns>
public static string GetPlatformName()
{
string strReturnPlatformName = string.Empty;
switch (Application.platform)
{
case RuntimePlatform.WindowsPlayer:
case RuntimePlatform.WindowsEditor:
strReturnPlatformName = "Win";
break;
case RuntimePlatform.IPhonePlayer:
strReturnPlatformName = "Iphone";
break;
case RuntimePlatform.Android:
strReturnPlatformName = "Android";
break;
default:
break;
}
return strReturnPlatformName;
}
}//Class_end
}
《2》單一AssetBundle包的載入與管理
/***
*
* Title: "AssetBundle工具包"專案
* 第1層: AB資源載入類
*
* Description:
* 功能:管理指定AssetBundle 中的資源
* 1:載入AssetBundle
* 2: 解除安裝、釋放AssetBundle 資源
* 3:檢視當前AssetBundle內資源
*
* Date: 2018
*
* Version: 1.0
*
* Modify Recorder:
*
*/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABTools
{
public class AssetLoader : System.IDisposable{
//當前AssetBundle
private AssetBundle _CurrentAssetBundle;
//容器鍵值對集合
private Hashtable _Ht;
/// <summary>
/// 建構函式
/// </summary>
/// <param name="abObj">給定AssetBundle</param>
public AssetLoader(AssetBundle abObj){
if (abObj!=null){
_CurrentAssetBundle = abObj;
_Ht = new Hashtable();
}
else
Debug.LogError(GetType()+ "/建構函式AssetLoader()/引數abObj==null!,請檢查!");
}
/// <summary>
/// 載入當前包中指定單個資源
/// 說明:帶有資源緩衝功能
/// </summary>
/// <param name="assetName"></param>
/// <returns></returns>
public UnityEngine.Object LoadAsset(string assetName,bool isCache=false){
return LoadResource<UnityEngine.Object>(assetName, isCache);
}
/// <summary>
/// 載入當前包資源,帶緩衝技術
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assetName"></param>
/// <param name="isCache"></param>
/// <returns></returns>
private T LoadResource<T>(string assetName, bool isCache) where T:UnityEngine.Object{
if (_Ht.Contains(assetName)){
return _Ht[assetName] as T;
}
T tmpTResource = _CurrentAssetBundle.LoadAsset<T>(assetName);
if (tmpTResource!=null && isCache)
{
_Ht.Add(assetName, tmpTResource);
}
else if(tmpTResource==null)
{
Debug.LogError(GetType() + "/LoadResource<T>()/引數tmpTResource==null!,請檢查!");
}
return tmpTResource;
}
/// <summary>
/// 解除安裝資源
/// 功能: 解除安裝指定AssetBundle 包中指定資源
/// </summary>
/// <param name="asset"></param>
/// <returns>
/// true: 表明解除安裝資源成功
/// </returns>
public bool UnLoadAsset(UnityEngine.Object asset)
{
if (asset!=null)
{
Resources.UnloadAsset(asset);
return true;
}
Debug.LogError(GetType() + "/UnLoadAsset()/引數asset==null!,請檢查!");
return false;
}
/// <summary>
/// 釋放當前AssetBundle資源(包)
/// </summary>
public void Dispose()
{
_CurrentAssetBundle.Unload(false);
}
/// <summary>
/// 釋放當前AssetBundle資源(包),且解除安裝所有資源
/// </summary>
public void DisposeALL()
{
_CurrentAssetBundle.Unload(true);
}
/// <summary>
/// 查詢當前AsserBundle 所有資源
/// </summary>
/// <returns></returns>
public string[] RetrivalALLAssetName()
{
return _CurrentAssetBundle.GetAllAssetNames();
}
}//Class_end
}
/***
*
* Title: "AssetBundle工具包"專案
* 第2層:WWW載入AssetBundle
*
* Description:
* 功能:
*
* Date: 2018
*
* Version: 1.0
*
* Modify Recorder:
*
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABTools
{
public class SingleABLoader:System.IDisposable
{
//引用類: 資源載入類
private AssetLoader _AssetLoader;
//委託: 載入完成
private DelLoadComplete _LoadCompleteHandle;
//AssetBundle名稱
private string _ABName;
//AssetBundle 下載路徑
private string _ABDownloadPath;
/// <summary>
/// 建構函式
/// </summary>
/// <param name="abName"></param>
/// <param name="loadProgress"></param>
/// <param name="loadComplete"></param>
public SingleABLoader(string abName, DelLoadComplete loadComplete)
{
_ABName = abName;
_LoadCompleteHandle = loadComplete;
_ABDownloadPath = PathTools.GetWWWPath() + "/" + _ABName;
_AssetLoader = null;
}
/// <summary>
/// 載入AssetBundle資源包
/// </summary>
/// <returns></returns>
public IEnumerator LoadAssetBundle(){
using (WWW www = new WWW(_ABDownloadPath)){
yield return www;
if (www.progress >= 1){
//載入完成,獲取AssetBundel例項
AssetBundle abObj = www.assetBundle;
if (abObj != null){
_AssetLoader = new AssetLoader(www.assetBundle);
if (_LoadCompleteHandle != null)
_LoadCompleteHandle(_ABName);
}
else{
Debug.LogError(GetType() + "/LoadAssetBundle()/WWW 下載出錯,請檢查 AssetBundle URL :" + _ABDownloadPath + " 錯誤資訊: " + www.error);
}
}
}//using_end
}//Method_end
/// <summary>
/// 載入(AB包內)資源
/// </summary>
/// <param name="assetName">資源名稱</param>
/// <param name="isCache">是否使用快取</param>
/// <returns></returns>
public UnityEngine.Object LoadAsset(string assetName,bool isCache)
{
if (_AssetLoader != null)
{
return _AssetLoader.LoadAsset(assetName, isCache);
}
Debug.LogError(GetType() + "/LoadAsset()/引數 _AssetLoader ==null!,請檢查!");
return null;
}
/// <summary>
/// 解除安裝(AB包內)資源
/// </summary>
/// <param name="asset">資源名稱</param>
public void UnLoadAsset(UnityEngine.Object asset)
{
if (_AssetLoader != null)
{
_AssetLoader.UnLoadAsset(asset);
}
else {
Debug.LogError(GetType() + "/UnLoadAsset()/引數 _AssetLoader ==null!,請檢查!");
}
}
/// <summary>
/// 釋放(AB包)
/// </summary>
public void Dispose()
{
if (_AssetLoader != null)
{
_AssetLoader.Dispose();
_AssetLoader = null;
}
else {
Debug.LogError(GetType() + "/Dispose()/引數 _AssetLoader ==null!,請檢查!");
}
}
/// <summary>
/// 釋放當前AssetBundle資源(包),且解除安裝所有資源
/// </summary>
public void DisposeALL()
{
if (_AssetLoader != null)
{
_AssetLoader.DisposeALL();
_AssetLoader = null;
}
else
{
Debug.LogError(GetType() + "/DisposeALL()/引數 _AssetLoader ==null!,請檢查!");
}
}
/// <summary>
/// 查詢當前AssetBundle包內所有資源
/// </summary>
/// <returns></returns>
public string[] RetrivalALLAssetName()
{
if (_AssetLoader != null)
{
return _AssetLoader.RetrivalALLAssetName();
}
Debug.LogError(GetType() + "/RetrivalALLAssetName()/引數 _AssetLoader ==null!,請檢查!");
return null;
}
}//Class_end
}
三、進行測試這個核心的框架內容
/***
*
* Title: "AssetBundle工具包"專案
* "AssetBundle框架"內部階段驗證測試
*
*
* Description:
* 檢測“SingleABLoader”類工作是否正常。
*
* Date: 20178
*
* Version: 1.0
*
* Modify Recorder:
*
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ABTools
{
public class SingleABLoader_TestClass:MonoBehaviour {
//引用類
SingleABLoader loaderObj = null;
//AB包名稱
private string _ABName1 = "commonscenes/prefabs_1.ab";
//AB包內資源名稱
private string _AssetName = "Cylinder";
private void Start(){
loaderObj = new SingleABLoader(_ABName1, LoadCompleate);
//載入AB資源包
StartCoroutine(loaderObj.LoadAssetBundle());
}
private void LoadCompleate(string abName){
Debug.Log("abName= " + abName + " 呼叫完畢!");
//載入資源
UnityEngine.Object tmpCloneObj= loaderObj.LoadAsset(_AssetName,false);
Instantiate(tmpCloneObj);
//顯示AB包內資源
string[] strArray = loaderObj.RetrivalALLAssetName();
Debug.Log("包內所有資源");
foreach (string item in strArray)
{
Debug.Log(item);
}
}
private void Update()
{
//釋放AB包
if (Input.GetKeyDown(KeyCode.A))
{
print("釋放AB包");
loaderObj.Dispose();
}
}
}//Class_end
}
注意:本內容來自《Unity3D/2D遊戲開發從0到1》第30章