1. 程式人生 > >Unity3D關於AssetBundle框架設計(B)

Unity3D關於AssetBundle框架設計(B)

一、AssetBundle整體管理

《1》AssetBundle框架的整體管理包含兩大部分

①主程式的AssetBundleMgr指令碼,通過呼叫輔助類“ABManifestLoader”來讀取Untiy提供的Manifest清單檔案。

②主程式的MutiABMgr指令碼,通過獲取Manifest清單檔案,迴圈遍歷需要載入AB包所有的底層依賴包。然後給每個AB包都記錄相關依賴於引用關係,這些關係都記錄在對應的ABRelation物件中。

框架資源包地址:https://download.csdn.net/download/xiaochenxihua/10761774

/***
 *
 *  Title: "AssetBundle工具包"專案
 *        輔助類: 讀取AssetBundles 依賴關係檔案:Win.Manifest
 *
 *  Description:
 *        功能:
 *             Win.Manifest 檔案是Unity提供的一份確定所有
 *             Assetbundle 包檔案所有依賴關係的清單檔案。
 *
 *  Date: 2018
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace ABTools
{
    public class ABManifestLoader:System.IDisposable {
        //本類例項
        private static ABManifestLoader _Instance;
        //AssetBundle(清單檔案)系統類
        private AssetBundleManifest _ManifestObj;
        //AssetBundle 清單檔案路徑
        private string _StrManifestPath;
        //讀取Manifest清單檔案的AssetBundle
        private AssetBundle _ABReadManifest;
        //是否載入完成
        private bool _IsLoadFinish;
        /* 只讀屬性 */
        public bool IsLoadFinish{
            get { return _IsLoadFinish; }
        }
        #region
        /// <summary>
        /// 建構函式
        /// </summary>
        private ABManifestLoader()
        {
            //確定清單WWW下載路徑
            _StrManifestPath = PathTools.GetWWWPath() + "/" + PathTools.GetPlatformName();
            _ManifestObj = null;
            _ABReadManifest = null;
            _IsLoadFinish = false;
        }

        /// <summary>
        /// 得到本類例項
        /// </summary>
        /// <returns></returns>
        public static ABManifestLoader GetInstance()
        {
            if(_Instance==null)
            {
                _Instance = new ABManifestLoader();
            }
            return _Instance;
        }
        #endregion
        /// 載入Manifest清單檔案
        public IEnumerator LoadManifestFile(){
            using (WWW www = new WWW(_StrManifestPath)){
                yield return www;
                if (www.progress >= 1){
                    //載入完成,獲取AssetBundel例項
                    AssetBundle abObj = www.assetBundle;
                    if (abObj != null){
                        _ABReadManifest = abObj;
                        _ManifestObj=_ABReadManifest.LoadAsset(ABDefine.ASSETBUNDLE_MANIFEST) as AssetBundleManifest;
                        _IsLoadFinish = true;
                    }
                    else{
                        Debug.LogError(GetType() + "/LoadManifestFile()/WWW 下載出錯,請檢查 AssetBundle URL :" + _StrManifestPath + " 錯誤資訊: " + www.error);
                    }
                }
            }//using_end
        }

        /// <summary>
        /// 返回"AssetBundleManifest"系統類例項
        /// </summary>
        /// <returns></returns>
        public AssetBundleManifest GetABManifest()
        {
            if (_IsLoadFinish)
            {
                if (_ManifestObj != null)
                {
                    return _ManifestObj;
                }
                else {
                    Debug.Log(GetType() + "/GetABManifest()/_ManifestObj==null  。請檢查原因!");
                }
            }
            else {
                Debug.Log(GetType() + "/GetABManifest()/Manifest沒有載入完畢,請檢查原因!");
            }
            return null;
        }

        /// <summary>
        /// 獲取指定AssetBundle包所有依賴項
        /// </summary>
        /// <param name="abName"></param>
        /// <returns></returns>
        public string[] RetrivalDependences(string abName)
        {
            if (_ManifestObj != null && !string.IsNullOrEmpty(abName))
            {
                return _ManifestObj.GetAllDependencies(abName);
            }
            return null;
        }

        /// <summary>
        /// 釋放資源(解除安裝Manifest所有資源)
        /// </summary>
        public void Dispose()
        {
            if (_ABReadManifest!=null)
            {
                _ABReadManifest.Unload(true);
            }
        }

    }//Class_end
}
/***
 *
 *  Title: "AssetBundle工具包"專案
 *        輔助類; AssetBundle 關係類
 *
 *  Description:
 *        功能:
 *            1:確定指定AssetBundle 類的依賴包。
 *            2:確定指定AssetBundle 類的引用包(被依賴包)
 *
 *  Date: 2018
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace ABTools
{
    public class ABRelation 
    {
        //AssetBundle 名稱
        private string _ABName;
        //所有依賴包名
        private List<string> _LisAllDependenceAB;
        //所有引用包名
        private List<string> _LisALLReferenceAB;

        /// 建構函式
        public ABRelation(string abName)
        {
            _ABName = abName;
            _LisAllDependenceAB = new List<string>();
            _LisALLReferenceAB = new List<string>();
        }

        /* 依賴關係 */
        #region 依賴關係
        /// <summary>
        /// 增加依賴關係
        /// </summary>
        /// <param name="abName">Assetbundle 名稱</param>
        public void AddDependence(string abName)
        {
            if (!_LisAllDependenceAB.Contains(abName))
            {
                _LisAllDependenceAB.Add(abName);
            }
        }

        /// <summary>
        /// 移除依賴關係
        /// </summary>
        /// <param name="abName"></param>
        /// <returns>
        /// true:  此AssetBundle沒有依賴項
        /// false: 此AssetBundle還有其他的依賴項
        /// </returns>
        public bool RemoveDependence(string abName)
        {
            if (_LisAllDependenceAB.Contains(abName))
            {
                _LisAllDependenceAB.Remove(abName);
            }
            if (_LisAllDependenceAB.Count > 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 獲取所有的依賴關係
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllDependences()
        {
            return _LisAllDependenceAB;
        }
        #endregion

        /* 引用關係 */
        #region 引用關係
        /// <summary>
        /// 增加引用關係
        /// </summary>
        /// <param name="abName"></param>
        public void AddReference(string abName)
        {
            if (!_LisALLReferenceAB.Contains(abName))
            {
                _LisALLReferenceAB.Add(abName);
            }
        }

        /// <summary>
        /// 移除引用關係
        /// </summary>
        /// <param name="abName"></param>
        /// <returns>
        /// true:  此AssetBundle沒有引用項
        /// false: 此AssetBundle還有其他的引用項
        /// </returns>
        public bool RemoveReference(string abName)
        {
            if (_LisALLReferenceAB.Contains(abName))
            {
                _LisALLReferenceAB.Remove(abName);
            }
            if (_LisALLReferenceAB.Count > 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 獲取所有的引用關係(集合)
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllReference()
        {
            return _LisALLReferenceAB;
        } 
        #endregion

    }//Class_end
}

 

/***
 *
 *  Title: "AssetBundle工具包"專案
 *         第4層(最後層): 所有“場景”的AssetBundle的管理
 *
 *  Description:
 *        功能:
 *            1:以“場景”為單位,管理整個專案所有的AssetBundle 包。
 *            2:提取“Menifest清單檔案”,快取本類。
 *
 *  Date: 2018
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace ABTools
{
    public class AssetBundleMgr: MonoBehaviour{
        //本類例項
        private static AssetBundleMgr _Instance;
        //場景集合
        private Dictionary<string, MultiABMgr> _DicAllScenes = new Dictionary<string, MultiABMgr>();
        //AssetBundle(清單檔案)系統類(包含本專案所有依賴項)
        private AssetBundleManifest _ManifestObj=null;

        #region
        private AssetBundleMgr() { }

        /// <summary>
        /// 得到本類例項
        /// </summary>
        /// <returns></returns>
        public static AssetBundleMgr GetInstance()
        {
            if (_Instance==null)
            {
                _Instance = new GameObject("_AssetBundleMgr").AddComponent<AssetBundleMgr>();
            }
            return _Instance;
        }

        private void Awake()
        {
            // 載入Manifest清單檔案
            StartCoroutine(ABManifestLoader.GetInstance().LoadManifestFile());
        }
        #endregion
        /// <summary>
        /// 下載AssetBundle指定包
        /// </summary>
        /// <param name="sceneName">場景名稱</param>
        /// <param name="abName">AssetBundle名稱</param>
        /// <param name="loadAllABCompleteHandle">AssetBundle名稱</param>
        public IEnumerator LoadAssetBundlePackage(string sceneName,string abName,DelLoadComplete loadAllABCompleteHandle)
        {
            //引數檢查
            if (string.IsNullOrEmpty(sceneName) || string.IsNullOrEmpty(abName))
            {
                Debug.LogError(GetType()+ "/LoadAssetBundlePackage()/scenenName Or abName is Null ,請檢查!");
                yield return null;
            }
            //等待Manifest清單載入完成
            while (!ABManifestLoader.GetInstance().IsLoadFinish)
                yield return null;
            //獲取“AssetBundle(清單檔案)系統類”
            _ManifestObj = ABManifestLoader.GetInstance().GetABManifest();
            //引數檢查
            if (_ManifestObj==null)
            {
                Debug.LogError(GetType() + "/LoadAssetBundlePackage()/_ManifestObj==null,請先確保載入Manifest清單檔案!");
                yield return null;
            }
            //如果不包含指定場景,則先建立
            if (!_DicAllScenes.ContainsKey(sceneName))
            {
                CreateScenesAB(sceneName,abName, loadAllABCompleteHandle);
            }

            //呼叫下一層(“多AssetBundle管理”類)
            MultiABMgr tmpMultiABMgrObj =_DicAllScenes[sceneName];
            if (tmpMultiABMgrObj==null)
            {
                Debug.LogError(GetType()+ "/LoadAssetBundlePackage()/tmpMultiABMgrObj==null , 請檢查!");
            }
            yield return tmpMultiABMgrObj.LoadAssetBundles(abName);
        }

        /// <summary>
        /// 建立一個“場景AssetBundle”且加入集合中 
        /// </summary>
        /// <param name="scensName"></param>
        private void CreateScenesAB(string scensName,string abName, DelLoadComplete loadAllABCompleteHandle)
        {
            MultiABMgr multiABMgeObj = new MultiABMgr(scensName, abName,loadAllABCompleteHandle);
            _DicAllScenes.Add(scensName,multiABMgeObj);
        }

        /// <summary>
        /// 載入(AB包內)資源
        /// </summary>
        /// <param name="scenesName">場景名稱</param>
        /// <param name="abName">AssetBundle 名稱</param>
        /// <param name="assetName">資源名稱</param>
        /// <param name="isCache">是否使用(資源)快取</param>
        /// <returns></returns>
        public UnityEngine.Object LoadAsset(string scenesName,string abName,string assetName, bool isCache)
        {
            if (_DicAllScenes.ContainsKey(scenesName))
            {
                MultiABMgr multiObj = _DicAllScenes[scenesName];
                return multiObj.LoadAsset(abName,assetName,isCache);
            }
            Debug.LogError(GetType()+"/LoadAsset()/找不到場景: "+scenesName+" ,無法載入AssetBundle 資源,請檢查!");
            return null;
        }

        /// <summary>
        /// 釋放一個場景中所有的資源
        /// </summary>
        /// <param name="scenesName"></param>
        /// <returns></returns>
        public void DisposeAllAssets(string scenesName)
        {
            if (_DicAllScenes.ContainsKey(scenesName))
            {
                MultiABMgr multiObj = _DicAllScenes[scenesName];
                multiObj.DisposeAllAsset();
            }
            else {
                Debug.LogError(GetType() + "/DisposeAllAsset()/找不到場景: " + scenesName + " ,無法釋放資源,請檢查!");
            }
        }

    }//Class_end
}
/***
 *
 *  Title: "AssetBundle工具包"專案
 *        第3層: (一個場景中)多AssetBundle管理
 *
 *  Description:
 *        功能:
 *            1:獲得包之間的依賴關係。
 *            2:管理具備依賴與引用關係的AssetBundle包的自動連鎖載入機制。
 *        
 *
 *  Date: 2018
 * 
 *  Version: 1.0
 *
 *  Modify Recorder:
 *     
 */

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace ABTools
{
    public class MultiABMgr
    {
        //當前 "單個AB載入實現類"
        private SingleABLoader _CurrentSingleABLoader;
        //"單個AB載入實現類"快取集合(作用: 快取AB包,防止重複載入)
        //第1個引數表示“AB包名稱”,第2引數是“單個AB載入實現類”
        private Dictionary<string, SingleABLoader> _DicSingleABLoaderCache;
        //當前場景名稱
        private string _CurrentScenesName;
        //當前AssetBundle 名稱
        private string _CurrentABName;
        //AB包名稱與對應依賴關係集合
        private Dictionary<string, ABRelation> _DicABRelation;
        //委託: 所有的AB包載入完成
        private DelLoadComplete _LoadAllABPackageCompleteHandle;




        /// <summary>
        /// 建構函式
        /// </summary>
        /// <param name="scenesName">場景名稱</param>
        /// <param name="abName">AssetBundle名稱</param>
        /// /// <param name="loadAllABPackageCompletteHandle">委託:載入所有AB包完成</param>
        public MultiABMgr(string scenesName,string abName,DelLoadComplete loadAllABPackageCompletteHandle) 
        {
            _CurrentScenesName = scenesName;
            _CurrentABName = abName;
            _DicSingleABLoaderCache = new Dictionary<string, SingleABLoader>();
            _DicABRelation = new Dictionary<string, ABRelation>();
            //委託:載入所有AB包完成
            _LoadAllABPackageCompleteHandle=loadAllABPackageCompletteHandle;
        }

        /// <summary>
        /// 完成指定AB包的呼叫
        /// </summary>
        /// <param name="abName"></param>
        private void CompletLoadAB(string abName)
        {
            if (abName.Equals(_CurrentABName))
            {
                if (_LoadAllABPackageCompleteHandle!=null)
                {
                    _LoadAllABPackageCompleteHandle(abName);
                }
            }
        }

        /// <summary>
        /// 載入AB包
        /// </summary>
        /// <param name="abName"></param>
        /// <returns></returns>
        public IEnumerator LoadAssetBundles(string abName)
        {
            if (!_DicABRelation.ContainsKey(abName))
            {
                ABRelation abRelationObj = new ABRelation(abName);
                _DicABRelation.Add(abName,abRelationObj);
            }
            ABRelation tmpABRelationObj = _DicABRelation[abName];
            //得到指定AB包所有的依賴關係
            string[] strDepencedArray = ABManifestLoader.GetInstance().RetrivalDependences(abName);
            foreach (string item_Depence in strDepencedArray)
            {
                //新增“依賴”項
                tmpABRelationObj.AddDependence(item_Depence);
                //新增“引用”項
                yield return LoadReference(item_Depence,abName);
            }

            //真正的AB包載入
            if (_DicSingleABLoaderCache.ContainsKey(abName))
            {
                yield return _DicSingleABLoaderCache[abName].LoadAssetBundle();
            }
            else {
                _CurrentSingleABLoader = new SingleABLoader(abName, CompletLoadAB);
                _DicSingleABLoaderCache.Add(abName,_CurrentSingleABLoader);
                yield return _CurrentSingleABLoader.LoadAssetBundle();
            }
        }//Method_end

        /// <summary>
        /// 載入引用AB包
        /// </summary>
        /// <param name="abName">AB包名稱</param>
        /// <param name="refABName">引用AB包名稱</param>
        /// <returns></returns>
        private IEnumerator LoadReference(string abName,string refABName)
        {
            //AB包已經載入了
            if (_DicABRelation.ContainsKey(abName))
            {
                ABRelation tmpABRelationObj = _DicABRelation[abName];
                //新增AB包的引用關係(被依賴)
                tmpABRelationObj.AddReference(refABName);
            }
            else {
                ABRelation tmpABRelationObj = new ABRelation(abName);
                tmpABRelationObj.AddReference(refABName);
                _DicABRelation.Add(abName,tmpABRelationObj);

                //開始載入依賴的包(注意: 這是一個“遞迴”呼叫)
                yield return LoadAssetBundles(abName);
            }
        }//Method_end

        /// <summary>
        /// 載入(AB包內)資源
        /// </summary>
        /// <param name="abName">AssetBundle 名稱</param>
        /// <param name="assetName">資源名稱</param>
        /// <param name="isCache">是否使用(資源)快取</param>
        /// <returns></returns>
        public UnityEngine.Object LoadAsset(string abName, string assetName, bool isCache)
        {
            foreach (string item_AbName in _DicSingleABLoaderCache.Keys)
            {
                if(item_AbName==abName)
                {
                    return _DicSingleABLoaderCache[item_AbName].LoadAsset(assetName,isCache);
                }
            }

            Debug.LogError(GetType() + "/LoadAsset()/找不到Assetbundle 包,無法載入資源,請檢查!   abName= "+abName+ "  assetName="+assetName);
            return null;
        }

        /// <summary>
        /// 釋放場景中所有資源
        /// </summary>
        /// <returns></returns>
        public void DisposeAllAsset()
        {
            //逐一釋放所有載入過的AssetBundle包資源
            try
            {
                foreach (SingleABLoader item_sABLoader in _DicSingleABLoaderCache.Values)
                {
                    item_sABLoader.DisposeALL();
                }
            }
            finally
            {
                _DicSingleABLoaderCache.Clear();
                _DicSingleABLoaderCache = null;

                /* 釋放其他物件佔用 */
                _DicABRelation.Clear();
                _DicABRelation = null;
                _CurrentScenesName = null;
                _CurrentABName = null;
                _LoadAllABPackageCompleteHandle = null;

                //解除安裝沒有使用到的資源
                Resources.UnloadUnusedAssets();
                //強制垃圾收集
                System.GC.Collect();
            }
        }

    }//Class_end
}

 

注:本內容來自《Untiy3D/2D遊戲開發從0到1》 第30章