工具類封裝
透過上文中對AB包載入API的瞭解和簡單使用,對AB包資源載入的幾種方法進行封裝,將其寫入單例類中,如程式碼展示。
確保每個AB資源包只載入一次:
在LoadAssetBundleManager 單例工具類中,首先提供基本的AB包及其AB包依賴包的載入方法,為保持AssetBundle只載入一次,使用DIctionary鍵值對來記錄已經載入出的AB資源。
主包路徑的靈活獲取:
載入主包路徑的獲取,採用宏來對不同的打包平臺來選擇對應的主包名稱。(可自行定義使用)
依賴包的載入:
透過載入主包中的AssetBundleManifest 來獲取目標AB包的依賴AB包名稱,根據名稱進行逐個載入。
載入方法有非同步和同步兩種:
非同步載入是在AB包獲取之後進行的資源的非同步載入,和同步載入一樣有對載入函式進行3此過載。分別為根據名稱載入,
泛型載入(C#中使用方便),根據型別載入(供Lua呼叫)。
解除安裝方法的實現:單個AB資源包解除安裝和所有資源包解除安裝兩種方式。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace BaseFramework
{
/// <summary>
/// 載入AssetBundle工具類 單例
/// </summary>
public class LoadAssetBundleManager: SingletonAutoMono<LoadAssetBundleManager>
{
//主AB包
private AssetBundle mainAssetBundle = null;
//包體依賴manifest
private AssetBundleManifest assetBundleManifest = null;
//防止AB包重複載入 對已經載入的AB包儲存
private Dictionary<string, AssetBundle> assetBundlesDic = new Dictionary<string, AssetBundle>();
//載入路徑
private string pathAssetBundle
{
get
{
return Application.streamingAssetsPath + "/";
}
}
//主包名稱
private string mainAssetBundleName
{
get
{
#if UnITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "StandaloneWindows";
#endif
}
}
/// <summary>
/// 根據名稱載入AB包 也會檢查相關依賴包 進行載入
/// </summary>
/// <param name="assetBundleName">AB包的名稱</param>
public void LoadAssetBundle(string assetBundleName)
{
if (!assetBundlesDic.ContainsKey(assetBundleName))
{
AssetBundle resAssetBundle = AssetBundle.LoadFromFile(pathAssetBundle+assetBundleName);
assetBundlesDic.Add(assetBundleName,resAssetBundle);
}
//載入主資源包 從主資源包中獲取對manifest
if (mainAssetBundle == null)
{
mainAssetBundle = AssetBundle.LoadFromFile(pathAssetBundle + mainAssetBundleName);
assetBundleManifest = mainAssetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
//載入目標資源包的依賴AB
string[] dependencies = assetBundleManifest.GetAllDependencies(assetBundleName);
foreach (var dependency in dependencies)
{
AssetBundle currentAB = null;
if (!assetBundlesDic.ContainsKey(dependency))
{
//載入依賴的ab包
currentAB = AssetBundle.LoadFromFile(pathAssetBundle + dependency);
assetBundlesDic.Add(dependency,currentAB);
}
}
}
/// <summary>
/// 從AB包中獲取具體資源
/// </summary>
/// <param name="abName">AB包名稱</param>
/// <param name="resName">資源名稱</param>
/// <returns>Object資源</returns>
public Object LoadResource(string abName, string resName)
{
LoadAssetBundle(abName);
Object resObj = null;
resObj = assetBundlesDic[abName].LoadAsset(resName);
return resObj;
}
/// <summary>
/// 泛型方法過載
/// </summary>
public T LoadResource<T>(string abName, string resName) where T:Object
{
LoadAssetBundle(abName);
T res = assetBundlesDic[abName].LoadAsset<T>(resName);
return res;
}
/// <summary>
/// 根據資源型別過載方法
/// </summary>
public Object LoadResource(string abName, string resName, System.Type type)
{
LoadAssetBundle(abName);
Object obj = assetBundlesDic[abName].LoadAsset(resName, type);
return obj;
}
//--------------------------------------------------------
//同步載入的AB包 非同步載入res資源
public void LoadResourceAsync(string abName, string resName, UnityAction<Object> callback)
{
StartCoroutine(LoadResourceIEn(abName, resName, callback));
}
//非同步載入協程
private IEnumerator LoadResourceIEn(string abName, string resName, UnityAction<Object> callback)
{
LoadAssetBundle(abName);
AssetBundleRequest request = assetBundlesDic[abName].LoadAssetAsync(resName);
yield return request;
callback(request.asset);
}
//根據泛型來非同步加資源
public void LoadResourceAsync<T>(string abName, string resName, UnityAction<Object> callback) where T : Object
{
StartCoroutine(LoadResourceIEn<T>(abName, resName, callback));
}
//非同步載入協程
private IEnumerator LoadResourceIEn<T>(string abName, string resName, UnityAction<Object> callback) where T :Object
{
LoadAssetBundle(abName);
AssetBundleRequest request = assetBundlesDic[abName].LoadAssetAsync<T>(resName);
yield return request;
callback(request.asset);
}
//根據res型別非同步載入資源
//根據泛型來非同步加資源
public void LoadResourceAsync(string abName, string resName, System.Type type,UnityAction<Object> callback)
{
StartCoroutine(LoadResourceIEn(abName, resName, type, callback));
}
//非同步載入協程
private IEnumerator LoadResourceIEn(string abName, string resName, System.Type type, UnityAction<Object> callback)
{
LoadAssetBundle(abName);
AssetBundleRequest request = assetBundlesDic[abName].LoadAssetAsync(resName,type);
yield return request;
callback(request.asset);
}
//資源包的解除安裝
public void UnLoadAssetBundle(string abName)
{
if (assetBundlesDic.ContainsKey(abName))
{
assetBundlesDic[abName].Unload(false);
assetBundlesDic.Remove(abName);
}
}
//解除安裝所有載入的資源包
public void UnLoadAllAssetBundle()
{
AssetBundle.UnloadAllAssetBundles(false);
assetBundlesDic.Clear();
mainAssetBundle = null;
assetBundleManifest = null;
}
}
}
該Manager繼承的單例指令碼:
using UnityEngine;
namespace BaseFramework
{
public class SingletonAutoMono<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance;
public static T Instance()
{
if (instance == null)
{
GameObject gameObject = new GameObject();
gameObject.name = typeof(T).ToString();
DontDestroyOnLoad(gameObject);
instance = gameObject.AddComponent<T>();
}
return instance;
}
}
}
在測試指令碼中我們使用6種不同的載入方式進行cube的載入,完成方法測試。
//測試使用工具類載入
Object cube = LoadAssetBundleManager.Instance().LoadResource("model", "cube");
if (cube is GameObject)
{
GameObject cube1 = cube as GameObject;
cube1.transform.position = Vector3.up;
Instantiate(cube1);
}
//非同步載入
LoadAssetBundleManager.Instance().LoadResourceAsync("model", "cube", (obj) =>
{
GameObject cube1 = obj as GameObject;
cube1.transform.position = new Vector3(0,1.5f,0);
Instantiate(cube1);
});
//重新測試
//使用泛型
GameObject cube2 = LoadAssetBundleManager.Instance().LoadResource<GameObject>("model", "cube");
cube2.transform.position = Vector3.left;
Instantiate(cube2);
LoadAssetBundleManager.Instance().LoadResourceAsync<GameObject>("model", "cube", (obj) =>
{
GameObject cube1 = obj as GameObject;
cube1.transform.position = Vector3.right;
Instantiate(cube1);
});
//透過型別載入測試
GameObject cube3 = LoadAssetBundleManager.Instance().LoadResource("model", "cube",typeof(GameObject)) as GameObject;
cube3.transform.position = new Vector3(0,-1.5f,0);
Instantiate(cube3);
LoadAssetBundleManager.Instance().LoadResourceAsync("model", "cube",typeof(GameObject), (obj) =>
{
GameObject cube1 = obj as GameObject;
cube1.transform.position = Vector3.zero;
Instantiate(cube1);
});
LoadAssetBundleManager.Instance().UnLoadAllAssetBundle();