Unity 熱更--AssetBundle學習筆記 1.0【AB包資源載入工具類的實現】

畅知發表於2024-05-03

工具類封裝

透過上文中對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();

image-20240502231345546

相關文章