Unity 热更--AssetBundle学习笔记 1.0【AB包资源加载工具类的实现】

工具类封装

通过上文中对AB包加载API的了解和简单使用,对AB包资源加载的几种方法进行封装,将其写入单例类中,如代码展示。

确保每个AB资源包只加载一次:

在LoadAssetBundleManager 单例工具类中,首先提供基本的AB包及其AB包依赖包的加载方法,为保持AssetBundle只加载一次,使用DIctionary键值对来记录已经加载出的AB资源。

主包路径的灵活获取:

加载主包路径的获取,采用宏来对不同的打包平台来选择对应的主包名称。(可自行定义使用)

依赖包的加载:

通过加载主包中的AssetBundleManifest 来获取目标AB包的依赖AB包名称,根据名称进行逐个加载。

加载方法有异步和同步两种:

异步加载是在AB包获取之后进行的资源的异步加载,和同步加载一样有对加载函数进行3此重载。分别为根据名称加载,

泛型加载(C#中使用方便),根据类型加载(供Lua调用)。

卸载方法的实现:单个AB资源包卸载和所有资源包卸载两种方式。

C# 复制代码
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继承的单例脚本:

C# 复制代码
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的加载,完成方法测试。

C# 复制代码
 //测试使用工具类加载
            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();