美文网首页
Unity AB管理

Unity AB管理

作者: ___________6a1d | 来源:发表于2021-06-18 08:06 被阅读0次

    Assetbundle管理

    核心:读配置表,依赖加载管理

    读取AssetBundle配置表
    设置中间类进行引用计数
    根据路径加载AssetBundle
    根据路径卸载AssetBundle
    为ResourceManager提供加载中间类,根据中间类释放资源,查找中间类等方法
    项目中新建一个空物体,名字为#StartCRT#,挂上以下脚本,用来加载配置文件:

    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    using UnityEngine;
    
    /// <summary>
    /// 加载AssetBundleConfig.bytes文件,这个必须在最开始运行
    /// </summary>
    public class StartCRT : MonoBehaviour
    {
        [HideInInspector]
        public byte[] bytes = null;
        [HideInInspector]
        public AssetBundleConfig config = null;
        // Use this for initialization
        void Start()
        {
            StartCoroutine(Load());
        }
     
        IEnumerator Load()
        {
            string path = Application.streamingAssetsPath + "/AssetBundleConfig.bytes";
            WWW www = new WWW(path);
            yield return www;
            if (www.isDone)
            {
                bytes = www.bytes;
                MemoryStream memoryStream = new MemoryStream(bytes);
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                config = (AssetBundleConfig)binaryFormatter.Deserialize(memoryStream);
                memoryStream.Close();
            }
        }
    }
    
    
    

    AB管理类

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
     
     /// <summary>
     /// AB管理类
     /// </summary>
    public class AssetBundleManager : Singleton<AssetBundleManager>
    {
        private StartCRT m_startCRT;//为了开启协成加载bytes文件
     
        /// <summary>
        /// 资源关系配置表
        /// 可以根据CRC找到对应资源块
        /// </summary>                                              
        protected Dictionary<uint, ResourceItem> m_ResourceItemDict = new Dictionary<uint, ResourceItem>();
        /// <summary>
        /// 储存已加载的AB包
        /// key为CRC
        /// </summary>
        protected Dictionary<uint, AssetBundleItem> m_AssetBundleItemDict = new Dictionary<uint, AssetBundleItem>();
        /// <summary>
        /// AssetBundleItem类对象池(因为有些对象经常可能用到)
        /// </summary>
        protected ClassObjectPool<AssetBundleItem> m_AssetBundleItemPool = ObjectManager.Instance.GetOrCreateClassPool<AssetBundleItem>(500);
        /// <summary>
        /// 加载AB配置表,返回是否正确加载,在游戏开始场景调用
        /// </summary>
        /// <returns></returns>
        public bool LoadAssetBundleConfig()
        {
            m_ResourceItemDict.Clear();
            m_startCRT = GameObject.Find("#StartCRT#").GetComponent<StartCRT>();
            if (m_startCRT.bytes == null)
            {
                Debug.LogError("AssetBundleConfig is not exist!");
                return false;
            }
     
            for (int i = 0; i < m_startCRT.config.ABList.Count; i++)
            {
                ABBase abBase = m_startCRT.config.ABList[i];
                //使用中间类进行保存
                ResourceItem item = new ResourceItem();
                item.m_Crc = abBase.Crc;
                item.m_AssetName = abBase.AssetName;
                item.m_ABName = abBase.ABName;
                item.m_DependedAssetBundle = abBase.ABDpendece;
                if (m_ResourceItemDict.ContainsKey(item.m_Crc))
                {
                    Debug.LogError("重复的CRC,资源名:" + item.m_AssetName + "AB包名:" + item.m_ABName);
                }
                else
                {
                    m_ResourceItemDict.Add(item.m_Crc, item);
                }
            }
            return true;
        }
        /// <summary>
        /// 根据路径的CRC加载中间类RecourseItem
        /// </summary>
        /// <param name="crc"></param>
        /// <returns></returns>
        public ResourceItem LoadResourceAssetBundle(uint crc)
        {
            ResourceItem item = null;
            //未找到资源的情况下
            if (!m_ResourceItemDict.TryGetValue(crc, out item) || item == null)
            {
                Debug.Log(string.Format("LoadResourceAssetBundle Error:can not find crc {0} in AssetBundleConfig", crc.ToString()));
                return item;
            }
            //证明这个ab被加载了,直接返回
            if (item.m_AssetBundle != null)
            {
                return item;
            }
            item.m_AssetBundle = LoadAssetBundle(item.m_ABName);
            //加载另外的AB
            if (item.m_DependedAssetBundle != null)
            {
                for (int i = 0; i < item.m_DependedAssetBundle.Count; i++)
                {
                    LoadAssetBundle(item.m_DependedAssetBundle[i]);
                }
            }
            return item;
        }
        /// <summary>
        /// 根据名字加载单个AssetBundle
        /// 有可能会出现这种情况,A和B都依赖了C资源,加载A和B的话就会加载两次(第二次会报错),如果卸载了A依赖的C,那B可能就显示不正常了
        /// 因此采用引用计数,加载时+1,判断卸载的时候引用计数为0的时候才让卸载
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private AssetBundle LoadAssetBundle(string name)
        {
            AssetBundleItem item = null;
            uint crc = Crc32.GetCrc32(name);
            if (!m_AssetBundleItemDict.TryGetValue(crc, out item))
            {
                AssetBundle ab = null;
                string fullPath = Application.streamingAssetsPath + "/" + name;
                if (File.Exists(fullPath))
                {
                    ab = AssetBundle.LoadFromFile(fullPath);
                }
                if (ab == null)
                {
                    Debug.LogError("LoadAssetBundle error:" + fullPath);
                }
                item = m_AssetBundleItemPool.Spawn(true);
                item.assetBundle = ab;
                item.refCount++;
                m_AssetBundleItemDict.Add(crc, item);
            }
            else
            {
                item.refCount++;
            }
     
            return item.assetBundle;
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="item"></param>
        public void ReleaseAsset(ResourceItem item)
        {
            if (item == null)
            {
                return;
            }
            if (item.m_DependedAssetBundle != null && item.m_DependedAssetBundle.Count >= 0)
            {
                for (int i = 0; i < item.m_DependedAssetBundle.Count; i++)
                {
                    UnLoadAssetBundle(item.m_DependedAssetBundle[i]);
                }
            }
            UnLoadAssetBundle(item.m_ABName);
        }
        /// <summary>
        /// 卸载依赖包
        /// </summary>
        /// <param name="name"></param>
        private void UnLoadAssetBundle(string name)
        {
            AssetBundleItem item = null;
            uint crc = Crc32.GetCrc32(name);
            if (m_AssetBundleItemDict.TryGetValue(crc, out item) && item != null)
            {
                item.refCount--;
                if (item.refCount <= 0 && item.assetBundle != null)
                {
                    item.assetBundle.Unload(true);
                    item.Reset();
                    m_AssetBundleItemPool.Recycle(item);
                    m_ResourceItemDict.Remove(crc);
                }
            }
        }
        /// <summary>
        /// 根据crc查找ResourcesItem
        /// </summary>
        /// <param name="crc"></param>
        /// <returns></returns>
        public ResourceItem FindResourceItem(uint crc)
        {
            return m_ResourceItemDict[crc];
        }
    }
    /// <summary>
    /// AB Item
    /// </summary>
    public class AssetBundleItem
    {
        public AssetBundle assetBundle = null;
        //引用计数
        public int refCount;
        //卸载时的话需要还原
        public void Reset()
        {
            assetBundle = null;
            refCount = 0;
        }
    }
    /// <summary>
    /// 资源item
    /// </summary>
    public class ResourceItem
    {
        /// <summary>
        /// 资源路径CRC
        /// </summary>
        public uint m_Crc = 0;
        /// <summary>
        /// 该资源文件名字
        /// </summary>
        public string m_AssetName = string.Empty;
        /// <summary>
        /// 该资源所在的AssetBundle名字
        /// </summary>
        public string m_ABName = string.Empty;
        /// <summary>
        /// 该资源所依赖的AssetBundle
        /// </summary>
        public List<string> m_DependedAssetBundle = null;
        /// <summary>
        /// 该资源所在的AssetBundle名字
        /// </summary>
        public AssetBundle m_AssetBundle = null;
    }
     
    
    

    相关文章

      网友评论

          本文标题:Unity AB管理

          本文链接:https://www.haomeiwen.com/subject/mimcyltx.html