zifa2003293 发表于 2023-3-1 13:57

Unity 资源加载框架(四) Assetbundle,音效等资源异步加载 ...

最近在写一本童话故事,欢迎点赞收藏,非常重要。给自己打个广告。以后会根据这本书开发一款游戏,文章有帮到你的话,请给书点个收藏。感谢。

1.ResourceManager 提供非gameobject 类资源加载(同步/异步)/释放 及ObjectManager加载Gameobject的加载接口
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace ABFrame
{


    /// <summary>
    /// 资源加载优先级
    /// </summary>
    public enum LoadResPriority
    {
      Res_Heigh = 0,//最高优先级
      Res_Middle,//一般优先级
      Res_Slow,//低优先级
      Res_Num,//优先级数量
    }


    /// <summary>
    /// 非实例化资源异步加载完回调委托
    /// </summary>
    public delegate void OnAsyncObjFinishDele(string path, Object obj, object param1 = null, object param2 = null, object param3 = null);
    /// <summary>
    /// 实例化资源异步加载完回调委托
    /// </summary>
    public delegate void OnAsyncInstanceFinishDele(string path, ResourceObj obj, object param1 = null, object param2 = null, object param3 = null);

    public class ResourceManager : Singleton<ResourceManager>
    {
      protected int m_Guid = 0;

      public bool m_IsLoadFromAssetBundle = false;

      /// <summary>
      /// 缓存正在使用的资源池
      /// </summary>
      public Dictionary<uint, ResourceItem> m_UsingAssetDic { get; set; } = new Dictionary<uint, ResourceItem>();

      /// <summary>
      /// 缓存引用计数为零的资源列表 达到缓存最大的时候 释放这个列表中最早没有使用的资源
      /// </summary>
      protected CMapList<ResourceItem> m_noRefResourceMapList = new CMapList<ResourceItem>();

      //==================================================异步=======================
      /// <summary>
      /// 使用Mono 开启协程进行异步加载
      /// </summary>
      protected MonoBehaviour m_asyncMono;
      ///正在异步加载的资源列表包含优先级
      protected List<AsyncLoadResInfo>[] m_AsyncLoadingAssetList = new List<AsyncLoadResInfo>[(int)LoadResPriority.Res_Num];
      ///正在异步加载的资源Dic 用来做重复判断
      protected Dictionary<uint, AsyncLoadResInfo> m_asnycloadingAssetDic = new Dictionary<uint, AsyncLoadResInfo>();
      /// <summary>
      /// 资源加载完成回调信息对象池
      /// </summary>
      protected ClassObjectPool<AsnycCallBackInfo> m_asyncCallBackInfoPool = new ClassObjectPool<AsnycCallBackInfo>(50);
      /// <summary>
      /// 异步加载资源信息对象池
      /// </summary>
      protected ClassObjectPool<AsyncLoadResInfo> m_asyncResInfoPool = new ClassObjectPool<AsyncLoadResInfo>(50);

      ///最长连续卡着的加载时间 微秒
      private const float MAXLOADRESTIME = 200000;
      /// <summary>
      /// 资源最大缓存个数 可以根据手机高低配置进行设置
      /// </summary>
      private const int MAXCACHECOUNT = 500;

      /// <summary>
      /// 异步加载初始化
      /// </summary>
      public void InitAsync(MonoBehaviour asyncMono)
      {
            for (int i = 0; i < (int)LoadResPriority.Res_Num; i++)
            {
                m_AsyncLoadingAssetList = new List&t;AsyncLoadResInfo>();
            }
            this.m_asyncMono = asyncMono;
            this.m_asyncMono.StartCoroutine(AsyncLoadCor());
      }


      /// <summary>
      /// 创建唯一的Guid
      /// </summary>
      /// <returns></returns>
      public int CreateGuid()
      {
            return this.m_Guid++;
      }

      
   
      //==============================================同步====================================


      /// <summary>
      /// 加载ResourceObj 针对ObjManager的接口
      /// </summary>
      /// <returns></returns>
      public ResourceObj LoadRecource(string path, ResourceObj resobj)
      {
            if (resobj == null) return null;
            uint crc = resobj.m_Crc == 0 ? Crc32.GetCrc32(path) : resobj.m_Crc;
            ResourceItem item = GetCatchResourceItem(crc);
            if (item != null)
            {
                resobj.m_ResItem = item;
                return resobj;
            }
            Object obj = null;
#if UNITY_EDITOR
            if (!m_IsLoadFromAssetBundle)
            {
                item = ABManager.Instance.FinResourceItemByCrc(crc);
                if (item != null && item.m_Obj != null)
                  obj = item.m_Obj as Object;
                else
                {
                  if (item == null)
                  {
                        item = new ResourceItem();
                        item.m_Crc = crc;
                  }
                  obj = LoadAssetByEditor<Object>(path);
                }

            }
#endif
            if (obj == null)
            {
                item = ABManager.Instance.LoadResourceAssetBundle(crc);
                if (item != null && item.m_AssetBundle != null)
                {
                  if (item.m_Obj != null) obj = item.m_Obj as Object;
                  else
                        obj = item.m_AssetBundle.LoadAsset<Object>(item.m_AssetName);
                }
            }
            CacheResource(path, ref item, crc, obj);

            resobj.m_ResItem = item;
            item.m_Clear = resobj.m_bClear;
            return resobj;
      }


      /// <summary>
      /// 同步加载资源 外部直接调用 仅加载不需要实例化的资源 例如texture,音频等等
      /// </summary>
      /// <typeparam name="T"></typeparam>
      /// <param name="path"></param>
      /// <returns></returns>
      public T LoadResource<T>(string path) where T : UnityEngine.Object
      {
            if (string.IsNullOrEmpty(path)) return null;

            uint crc = Crc32.GetCrc32(path);
            ResourceItem item = GetCatchResourceItem(crc);
            if (item != null)
            {
                return item.m_Obj as T;
            }
            T obj = null;
#if UNITY_EDITOR
            if (!m_IsLoadFromAssetBundle)
            {
                item = ABManager.Instance.FinResourceItemByCrc(crc);
                if (item == null)
                  Debug.LogError("not found assets " + path);
                else
                {
                  if (item.m_Obj != null) obj = item.m_Obj as T;
                  else obj = LoadAssetByEditor<T>(path);
                }
            }
#endif
            if (obj == null)
            {
                item = ABManager.Instance.LoadResourceAssetBundle(crc);
                if (item != null && item.m_AssetBundle != null)
                {
                  if (item.m_Obj != null) obj = item.m_Obj as T;
                  else
                        obj = item.m_AssetBundle.LoadAsset<T>(item.m_AssetName);
                }
            }
            CacheResource(path, ref item, crc, obj);
            return obj;
      }


      /// <summary>
      /// 根据ResourceObj 卸载资源
      /// </summary>
      /// <returns></returns>
      public bool ReleaseResource(ResourceObj obj, bool destoryobj = false)
      {
            if (obj == null) return false;
            ResourceItem item = null;

            if (!m_UsingAssetDic.TryGetValue(obj.m_Crc, out item) || item == null)
                Debug.LogError("m_UsingAssetDic 里不存在该资源:" + obj.m_CloneObj.name + " 可能释放了多次");

            GameObject.Destroy(obj.m_CloneObj);
            item.RefCount--;
            DestoryResourceItem(item, destoryobj);
            return true;
      }


      /// <summary>
      /// 不需要实例化的资源的卸载
      /// </summary>
      /// <param name="obj"></param>
      /// <param name="destoryObj"></param>
      /// <returns></returns>
      public bool ReleaseResource(Object obj, bool destoryObj = false)
      {
            if (obj == null) return false;
            ResourceItem item = null;
            foreach (ResourceItem res in m_UsingAssetDic.Values)
            {
                if (res.m_Guid == obj.GetInstanceID())
                  item = res;
            }

            if (item == null)
            {
                Debug.LogError("AssetDic 不存在该资源:" + obj.name + " 可能释放了多次");
                return false;
            }

            item.RefCount--;
            DestoryResourceItem(item, destoryObj);
            return true;
      }

      /// <summary>
      /// 释放资源 根据资源路径
      /// </summary>
      /// <param name="path"></param>
      /// <param name="destoryObj"></param>
      /// <returns></returns>
      public bool ReleaseResource(string path, bool destoryObj = false)
      {
            if (string.IsNullOrEmpty(path)) return false;
            uint crc = Crc32.GetCrc32(path);
            ResourceItem item = null;
            if (!m_UsingAssetDic.TryGetValue(crc, out item) || item == null)
            {
                Debug.LogError("AssetDic 里不存在该资源:" + path + " 可能释放了多次");
                return false;
            }

            item.RefCount--;
            DestoryResourceItem(item, destoryObj);
            return true;
      }

      /// <summary>
      /// 清空缓存 一般在跳场景时候使用
      /// </summary>
      public void ClearCache()
      {
            List<ResourceItem> tempList = new List<ResourceItem>();
            foreach (ResourceItem item in m_UsingAssetDic.Values)
            {
                if (item.m_Clear)
                  tempList.Add(item);
            }
            foreach (var item in tempList)
            {
                DestoryResourceItem(item, true);
            }
            tempList.Clear();
      }

      /// <summary>
      /// 根据obj 增加引用计数
      /// </summary>
      /// <returns></returns>
      public int IncreaseResourceRef(ResourceObj resobj, int count = 1)
      {
            return resobj == null ? 0 : IncreaseResourceRef(resobj.m_Crc, count);
      }

      /// <summary>
      /// 根据path 增加引用计数
      /// </summary>
      /// <param name="crc"></param>
      /// <param name="count"></param>
      /// <returns></returns>
      public int IncreaseResourceRef(uint crc, int count = 1)
      {
            ResourceItem item = null;
            if (!m_UsingAssetDic.TryGetValue(crc, out item) || item == null) return 0;
            item.RefCount += count;
            item.m_LastUseTime = Time.realtimeSinceStartup;
            return item.RefCount;
      }

      /// <summary>
      /// 减少引用计数
      /// </summary>
      /// <returns></returns>
      public int DecreaseResourceRef(ResourceObj resobj, int count = 1)
      {
            return resobj == null ? 0 : DecreaseResourceRef(resobj.m_Crc, count);
      }

      /// <summary>
      /// 根据路径减少引用计数
      /// </summary>
      /// <param name="crc"></param>
      /// <param name="count"></param>
      /// <returns></returns>
      public int DecreaseResourceRef(uint crc, int count = 1)
      {
            ResourceItem item = null;
            if (!m_UsingAssetDic.TryGetValue(crc, out item) || item == null) return 0;
            item.RefCount -= count;
            return item.RefCount;
      }

      /// <summary>
      ///取消异步加载
      /// </summary>
      public bool CancelAsyncLoad(ResourceObj res)
      {
            AsyncLoadResInfo asyinfo = null;
            if (m_asnycloadingAssetDic.TryGetValue(res.m_Crc, out asyinfo) && m_AsyncLoadingAssetList[(int)asyinfo.m_Priority].Contains(asyinfo))
            {
                //取消所有加载完成回调
                for (int i = asyinfo.m_DeleFinishCallBacks.Count - 1; i >= 0; i--)
                {
                  AsnycCallBackInfo tempcallback = asyinfo.m_DeleFinishCallBacks;
                  if (tempcallback != null && res == tempcallback.m_ResObj)
                  {
                        tempcallback.Reset();
                        m_asyncCallBackInfoPool.Recycle(tempcallback);
                        asyinfo.m_DeleFinishCallBacks.Remove(tempcallback);
                  }
                }
                if (asyinfo.m_DeleFinishCallBacks.Count <= 0)
                {
                  asyinfo.Reset();
                  m_AsyncLoadingAssetList[(int)asyinfo.m_Priority].Remove(asyinfo);
                  m_asyncResInfoPool.Recycle(asyinfo);
                  m_asnycloadingAssetDic.Remove(res.m_Crc);
                  return true;
                }
            }
            return false;
      }


      /// <summary>
      /// 预加载资源 贴图音效等资源
      /// </summary>
      /// <param name="path"></param>
      public void PreLoadRes(string path)
      {
            if (string.IsNullOrEmpty(path)) return;

            uint crc = Crc32.GetCrc32(path);
            //预加载不需要引用计数
            ResourceItem item = GetCatchResourceItem(crc, 0);
            if (item != null) return;

            Object obj = null;
#if UNITY_EDITOR
            if (!m_IsLoadFromAssetBundle)
            {
                item = ABManager.Instance.FinResourceItemByCrc(crc);
                if (item.m_Obj != null) obj = item.m_Obj;
                else
                {
                  obj = LoadAssetByEditor<Object>(path);
                }
            }
#endif
            if (obj == null)
            {
                item = ABManager.Instance.LoadResourceAssetBundle(crc);
                if (item != null && item.m_AssetBundle != null)
                {
                  if (item.m_Obj != null) obj = item.m_Obj;
                  else
                        obj = item.m_AssetBundle.LoadAsset<Object>(item.m_AssetName);
                }
            }
            CacheResource(path, ref item, crc, obj);
            //跳场景不清除缓存
            item.m_Clear = false;
            ReleaseResource(obj, false);
      }

      /// <summary>
      /// 缓存加载的资源
      /// </summary>
      /// <param name="path"></param>
      /// <param name="item"></param>
      /// <param name="crc"></param>
      /// <param name="obj"></param>
      /// <param name="addrefcount"></param>
      void CacheResource(string path, ref ResourceItem item, uint crc, Object obj, int addrefcount = 1)
      {
            if (item == null)
            {
                Debug.LogError("ResourceItem Load Failpath:" + path);
                return;
            }
            //当缓存达到最大数量时 清空缓存
            WashOut();
            if (obj == null)
                Debug.LogError("ResourceLoad Failpath:" + path);
            item.m_Obj = obj;
            item.m_Guid = obj.GetInstanceID();
            item.m_LastUseTime = Time.realtimeSinceStartup;
            item.m_Crc = crc;
            item.RefCount += addrefcount;

            ResourceItem oldItem = null;
            if (m_UsingAssetDic.TryGetValue(crc, out oldItem))
            {
                m_UsingAssetDic = item;
            }
            else
            {
                m_UsingAssetDic.Add(item.m_Crc, item);
            }
      }


      /// <summary>
      /// 缓存太多 清除最早没有使用的资源 当内存不足的时候进行清除缓存操作 根据手机内存大小进行判断
      /// </summary>
      protected void WashOut()
      {
            //当大于缓存个数时 进行一般资源释放
            if (m_noRefResourceMapList.Size() > MAXCACHECOUNT)
            {
                for (int i = 0; i < MAXCACHECOUNT / 2; i++)
                {
                  ResourceItem item = m_noRefResourceMapList.Back();
                  DestoryResourceItem(item, true);
                }
            }

      }

      /// <summary>
      /// 回收资源
      /// </summary>
      /// <param name="item"></param>
      /// <param name="destory"></param>
      protected void DestoryResourceItem(ResourceItem item, bool destoryCache = false)
      {
            //判断引用计数 是否还在被其他资源使用
            if (item == null || item.RefCount > 0) return;

            //缓存
            if (!destoryCache)
            {
                //加入到双向链表表头
                m_noRefResourceMapList.InsertToHead(item);
                return;
            }

            if (!m_UsingAssetDic.Remove(item.m_Crc)) return;
            //从双向链表中移出
            m_noRefResourceMapList.Remove(item);
            //不缓存 清空assetbundle 引用
            ABManager.Instance.ReleaseAssetBundle(item);

            //清空资源对应的对象池
            ObjectManager.Instance.ClearPoolObject(item.m_Crc);

            if (item.m_Obj != null) item.m_Obj = null;
#if UNITY_EDITOR
            Resources.UnloadUnusedAssets();
#endif

      }

#if UNITY_EDITOR
      protected T LoadAssetByEditor<T>(string path) where T : UnityEngine.Object
      {
            return UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path);
      }
#endif


      ResourceItem GetCatchResourceItem(uint crc, int addrefcount = 1)
      {
            ResourceItem item = null;
            if (m_UsingAssetDic.TryGetValue(crc, out item))
            {
                if (item != null)
                {
                  item.RefCount += addrefcount;
                  item.m_LastUseTime = Time.realtimeSinceStartup;
                  //if (item.RefCount<=1)
                  //{
                  //    m_resourceMapList.Remove(item);
                  //}
                }
            }

            return item;
      }
    }




    /// <summary>
    /// 双向链表封装
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CMapList<T> where T : class, new()
    {
      public DoubleLinkList<T> m_DLinkList = new DoubleLinkList<T>();

      /// <summary>
      /// 要用到的值 和它所在链表中的节点
      /// </summary>
      Dictionary<T, DoubleLinkListNode<T>> m_findNodeDic = new Dictionary<T, DoubleLinkListNode<T>>();

      /// <summary>
      ///析构函数 销毁时会调用
      /// </summary>
      ~CMapList()
      {
            Clear();
      }

      /// <summary>
      /// 插入节点到头部
      /// </summary>
      /// <param name="t"></param>
      public void InsertToHead(T t)
      {
            DoubleLinkListNode<T> node = null;
            if (m_findNodeDic.TryGetValue(t, out node) && node != null)
            {
                m_DLinkList.AddToHead(node);
                return;
            }
            m_DLinkList.AddToHead(t);
            m_findNodeDic.Add(t, m_DLinkList.m_HeadNode);
      }


      /// <summary>
      /// 从表尾取出一个节点
      /// </summary>
      public void Pop()
      {
            if (m_DLinkList.m_TailNode != null)
                Remove(m_DLinkList.m_TailNode.m_CurrentValue);
      }

      /// <summary>
      ///移除
      /// </summary>
      public void Remove(T t)
      {
            DoubleLinkListNode<T> node = null;
            if (!m_findNodeDic.TryGetValue(t, out node) || node == null)
                return;
            m_DLinkList.RemoveNode(node);
            m_findNodeDic.Remove(t);
      }


      /// <summary>
      /// 清空链表
      /// </summary>
      public void Clear()
      {
            while (m_DLinkList.m_TailNode != null)
            {
                Remove(m_DLinkList.m_TailNode.m_CurrentValue);
            }
      }


      /// <summary>
      /// 获取尾部节点
      /// </summary>
      /// <returns></returns>
      public T Back()
      {
            return m_DLinkList.m_TailNode == null ? null : m_DLinkList.m_TailNode.m_CurrentValue;
      }


      /// <summary>
      /// 节点个数
      /// </summary>
      /// <returns></returns>
      public int Size()
      {
            return m_findNodeDic.Count;
      }


      /// <summary>
      /// 查找节点是否存在
      /// </summary>
      /// <param name="t"></param>
      /// <returns></returns>
      public bool Find(T t)
      {
            DoubleLinkListNode<T> node = null;
            if (!m_findNodeDic.TryGetValue(t, out node) || node == null)
                return false;
            return true;
      }

      /// <summary>
      /// 刷新某个节点 把节点移动到前面去
      /// </summary>
      /// <param name="t"></param>
      /// <returns></returns>
      public bool Reflesh(T t)
      {
            DoubleLinkListNode<T> node = null;
            if (!m_findNodeDic.TryGetValue(t, out node) || node == null)
                return false;
            m_DLinkList.MoveToHead(node);
            return true;
      }

    }
}
2.ObjectManager 提供Gameobject类 预制体的加载 卸载
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace ABFrame
{

public class ObjectManager : Singleton<ObjectManager>
{
    /// <summary>
    /// 对象池节点
    /// </summary>
    protected Transform m_RecycleTs;
    /// <summary>
    /// 场景节点
    /// </summary>
    protected Transform m_SceneTs;

    /// <summary>
    /// 使用中的对象 对象池
    /// </summary>
    protected Dictionary<uint, List<ResourceObj>> m_ObjectPoolDic = new Dictionary<uint, List<ResourceObj>>();
    /// <summary>
    /// 暂存的Resourceobj Dic
    /// </summary>
    protected Dictionary<int, ResourceObj> m_RescourceObjDic = new Dictionary<int, ResourceObj>();
    /// <summary>
    /// ResourceObj 对象池
    /// </summary>
    protected ClassObjectPool<ResourceObj> m_ResourceObjPool = null;
    /// <summary>
    /// 根据异步的guid 存储ResourceObj 来判断是否时异步加载
    /// </summary>
    protected Dictionary<int, ResourceObj> m_AsyncResObjs = new Dictionary<int, ResourceObj>();

    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="recyclets"></param>
    public void Init(Transform recyclets,Transform scenets)
    {
      m_ResourceObjPool = ObjectManager.Instance.GetOrCreateClassPool<ResourceObj>( 500);
      this.m_RecycleTs = recyclets;
      this.m_RecycleTs.gameObject.SetActive(false);
      this.m_SceneTs = scenets;
    }

    /// <summary>
    /// 清空对象池
    /// </summary>
    public void ClearCache()
    {
      List<uint> tempList = new List<uint>();

      foreach (uint key in m_ObjectPoolDic.Keys)
      {
            List<ResourceObj> resobjlist = m_ObjectPoolDic;
            for (int i = resobjlist.Count-1; i >=0; i--)
            {
                ResourceObj obj=resobjlist;
                //可以克隆 且 可以被清除
                if (!System.Object.ReferenceEquals(obj.m_CloneObj,null)&&obj.m_bClear)
                {
                  resobjlist.Remove(obj);
                  m_RescourceObjDic.Remove(obj.m_CloneObj.GetInstanceID());
                  GameObject.Destroy(obj.m_CloneObj);
                  obj.Reset();
                  m_ResourceObjPool.Recycle(obj);
                }
            }
            ///判断资源是否全部被清除
            if (resobjlist.Count<=0)
            {
                tempList.Add(key);
            }
      }

      ///清除已经卸载 的资源对象池
      for (int i = 0; i < tempList.Count; i++)
      {
            uint tempcrc = tempList;
            if (m_ObjectPoolDic.ContainsKey(tempcrc))
            {
                m_ObjectPoolDic.Remove(tempcrc);
            }
      }
      tempList.Clear();
    }


    /// <summary>
    /// 清除某个资源再对象池中所有的资源
    /// </summary>
    public void ClearPoolObject(uint crc)
    {
      List<ResourceObj> reslist = null;
      if (!m_ObjectPoolDic.TryGetValue(crc, out reslist) || reslist == null) return;

      for (int i = reslist.Count-1; i >=0; i--)
      {
            ResourceObj resobj = reslist;
            //资源可以被清除
            if (resobj.m_bClear)
            {
                reslist.Remove(resobj);
                int tempId = resobj.m_CloneObj.GetInstanceID();
                GameObject.Destroy(resobj.m_CloneObj);
                resobj.Reset();
                m_RescourceObjDic.Remove(tempId);
                m_ResourceObjPool.Recycle(resobj);
            }
      }
      //对象池中的资源为0进行删除
      if (reslist.Count<=0)
      {
            m_ObjectPoolDic.Remove(crc);
      }
    }

    /// <summary>
    /// 根据对象实例直接获取离线数据
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public OffLineData FindOffLineData(GameObject obj)
    {
      OffLineData offLineData = null;
      ResourceObj resobj = null;
      m_RescourceObjDic.TryGetValue(obj.GetInstanceID(),out resobj);
      if (resobj!=null)
      {
            offLineData = resobj.m_offLineData;
      }
      return offLineData;
    }


    /// <summary>
    /// 从对象池里面取对象
    /// </summary>
    /// <param name="path"></param>
    /// <param name="bclear"></param>
    /// <returns></returns>
    protected ResourceObj GetResourceObjFromPool(uint crc)
    {
      List<ResourceObj> list = null;
      if (this.m_ObjectPoolDic.TryGetValue(crc,out list)&&list!=null&&list.Count>0)
      {
            ///resourceManager 的引用计数
            ResourceManager.Instance.IncreaseResourceRef(crc);
            ResourceObj resourceObj = list;
            list.RemoveAt(0);
            GameObject obj = resourceObj.m_CloneObj;
            if (!System.Object.ReferenceEquals(obj,null))
            {
                if (!System.Object.ReferenceEquals(resourceObj.m_offLineData,null))
                {
                  resourceObj.m_offLineData.ResetPrpo();
                }
                resourceObj.m_Already = false;
#if UNITY_EDITOR
                if (obj.name.EndsWith("(Recycle)"))
                {
                  obj.name = obj.name.Replace("(Recycle)","");
                }
#endif
            }
            return resourceObj;
      }
      return null;
    }

    /// <summary>
    /// 取下异步加载
    /// </summary>
    public void CancelAsyncLoad(int guid)
    {
      ResourceObj resobj = null;
      if (m_AsyncResObjs.TryGetValue(guid,out resobj)&&ResourceManager.Instance.CancelAsyncLoad(resobj))
      {
            m_AsyncResObjs.Remove(guid);
            resobj.Reset();
            m_ResourceObjPool.Recycle(resobj);
      }
    }


    /// <summary>
    /// 是否正在异步加载
    /// </summary>
    /// <returns></returns>
    public bool IsAsyncLoading(int guid)
    {
      return m_AsyncResObjs.ContainsKey(guid);
    }


    /// <summary>
    /// 该对象是否是对象池创建的
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public bool IsObjectManangerCreate(GameObject obj)
    {
      int guid = obj.GetInstanceID();
      return m_RescourceObjDic.ContainsKey(guid);
    }



    /// <summary>
    /// 预加载路径
    /// </summary>
    /// <param name="path">路径</param>
    /// <param name="count">预加载个数</param>
    /// <param name="clear">场景跳转是否清除</param>
    public void PreLoadGameobject(string path,int count=1,bool clear=false)
    {
      List<GameObject> tempGameobjectList = new List<GameObject>();
      for (int i = 0; i < count; i++)
      {
            GameObject obj = InstantiateObject(path,false,clear);
            tempGameobjectList.Add(obj);
      }
      for (int i = 0; i < count; i++)
      {
            GameObject obj = tempGameobjectList;
            ReleaseObject(obj);
            obj = null;
      }
      tempGameobjectList.Clear();
    }

    /// <summary>
    /// 同步加载
    /// </summary>
    /// <param name="path"></param>
    /// <param name="bclear"></param>
    /// <returns></returns>
    public GameObject InstantiateObject(string path, bool isSceneObj=false,bool bclear = true)
    {
      uint crc = Crc32.GetCrc32(path);
      ResourceObj resourceObj = GetResourceObjFromPool(crc);
      if (resourceObj==null)
      {
            resourceObj = m_ResourceObjPool.Spwan(true);
            resourceObj.m_Crc = crc;
            resourceObj.m_bClear = bclear;
            //resourcemanager提供加载方法
            resourceObj= ResourceManager.Instance.LoadRecource(path, resourceObj);
            if (resourceObj.m_ResItem.m_Obj != null)
            {
                resourceObj.m_CloneObj = GameObject.Instantiate(resourceObj.m_ResItem.m_Obj) as GameObject;
                ///赋值离线加载数据
                resourceObj.m_offLineData = resourceObj.m_CloneObj.GetComponent<OffLineData>();
            }
      }
      if (isSceneObj) resourceObj.m_CloneObj.transform.SetParent(this.m_SceneTs, false);

      int tempId = resourceObj.m_CloneObj.GetInstanceID();
      if (!m_RescourceObjDic.ContainsKey(tempId))
            m_RescourceObjDic.Add(tempId,resourceObj);

      return resourceObj.m_CloneObj;
    }

    /// <summary>
    /// 异步资源加载
    /// </summary>
    /// <param name="path"></param>
    /// <param name="finishCallback">加载完成回调</param>
    /// <param name="loadResPriority"></param>
    /// <param name="isSceneObj"></param>
    /// <param name="param1"></param>
    /// <param name="param2"></param>
    /// <param name="param3"></param>
    /// <param name="bclear">跳场景是否删除</param>
    /// <returns></returns>
    public long InstantiateObjectAsync(string path, OnAsyncObjFinishDele finishCallback, LoadResPriority loadResPriority, bool isSceneObj = false, object param1 = null, object param2 = null, object param3 = null, bool bclear=true)
    {
      if (string.IsNullOrEmpty(path)) return 0;
      uint crc = Crc32.GetCrc32(path);
      ResourceObj obj = GetResourceObjFromPool(crc);
      if (obj!=null)
      {
            if (isSceneObj)
                obj.m_CloneObj.transform.SetParent(this.m_SceneTs,false);
            finishCallback?.Invoke(path, obj.m_CloneObj, param1, param2, param3);
            return obj.m_Guid;
      }

      int guid = ResourceManager.Instance.CreateGuid();
      obj = m_ResourceObjPool.Spwan(true);
      obj.m_Crc = crc;
      obj.m_bClear = bclear;
      obj.m_setSceneParent = isSceneObj;
      obj.m_FinishCallback = finishCallback;
      obj.m_Guid = guid;
      obj.Param1 = param1;
      obj.Param2 =param2;
      obj.Param3 = param3;

      //调用resourmanager 异步加载
      ResourceManager.Instance.AsnycLoadInstanceResource(path,obj, OnLoadInstanceObjFinish, loadResPriority,param1,param2,param3,crc);

      return guid;
    }

    /// <summary>
    ///当实例化资源加载完毕时的回调
    /// </summary>
    /// <param name="path">路径</param>
    /// <param name="obj">中间类</param>
    /// <param name="param1"></param>
    /// <param name="param2"></param>
    /// <param name="param3"></param>
    protected void OnLoadInstanceObjFinish(string path, ResourceObj resobj, object param1 = null, object param2 = null, object param3 = null)
    {
      if (resobj == null) return;
      if (resobj.m_ResItem.m_Obj==null)
      {
#if UNITY_EDITOR
            Debug.LogError("异步加载实例化资源错误:"+path);
#endif
      }
      else
      {
            resobj.m_CloneObj = GameObject.Instantiate(resobj.m_ResItem.m_Obj) as GameObject;
            ///赋值离线加载数据
            resobj.m_offLineData = resobj.m_CloneObj.GetComponent<OffLineData>();
      }
      if (resobj.m_CloneObj!=null&&resobj.m_setSceneParent)
      {
            resobj.m_CloneObj.transform.SetParent(this.m_SceneTs,false);
      }

      ///加载完成从正在加载的异步中移除
      if (m_AsyncResObjs.ContainsKey(resobj.m_Guid))
      {
            m_AsyncResObjs.Remove(resobj.m_Guid);
      }


      if (resobj.m_FinishCallback!=null)
      {
            int tempId = resobj.m_CloneObj.GetInstanceID();
            if (!m_RescourceObjDic.ContainsKey(tempId))
            {
                m_RescourceObjDic.Add(tempId,resobj);
            }
            resobj.m_FinishCallback(path,resobj.m_CloneObj,param1,param2,param3);
      }
    }

    /// <summary>
    ///回收资源
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="maxCacheCount"></param>
    /// <param name="destorycache"></param>
    /// <param name="recycleParent"></param>
    public void ReleaseObject(GameObject obj,int maxCacheCount=-1,bool destorycache=false,bool recycleParent=true)
    {
      if (obj == null) return;
      int guid = obj.GetInstanceID();

      ResourceObj resobj = null;
      if (!m_RescourceObjDic.TryGetValue(guid,out resobj))
      {
            Debug.LogError("对象不是ObjectManager 创建的" +obj.name);
            return;
      }

      if (resobj==null)
      {
            Debug.LogError("缓存的ResourceObj为空");
            return;
      }

      if (resobj.m_Already)
      {
            Debug.LogError("该对象已经放回对象池了 检查自己是否清空引用!");
            return;
      }

#if UNITY_EDITOR
      obj.name += "(Recycle)";
#endif
      List<ResourceObj> list = null;
      ///不缓存
      if (maxCacheCount==0)
      {
            m_RescourceObjDic.Remove(guid);
            ResourceManager.Instance.ReleaseResource(resobj,destorycache);
            resobj.Reset();
            m_ResourceObjPool.Recycle(resobj);
      }
      //回收到对象池
      else
      {
            if (!m_ObjectPoolDic.TryGetValue(resobj.m_Crc,out list)||list==null)
            {
                list = new List<ResourceObj>();
                m_ObjectPoolDic.Add(resobj.m_Crc,list);
            }
            if (resobj.m_CloneObj)
            {
                if (recycleParent)
                  resobj.m_CloneObj.transform.SetParent(this.m_RecycleTs);
                else
                  resobj.m_CloneObj.SetActive(false);
            }
            if (maxCacheCount < 0 ||list.Count < maxCacheCount)
            {
                list.Add(resobj);
                resobj.m_Already = true;
                //resourceManager 做一个引用计数
                ResourceManager.Instance.DecreaseResourceRef(resobj);
            }
            //达到最大缓存个数
            else
            {
                m_RescourceObjDic.Remove(guid);
                ResourceManager.Instance.ReleaseResource(resobj, destorycache);
                resobj.Reset();
                m_ResourceObjPool.Recycle(resobj);
            }
      }
    }



    #region 类对象池使用

    protected Dictionary<Type, object> m_ClassPoolDic = new Dictionary<Type, object>();
    /// <summary>
    /// 创建类对象池
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="max"></param>
    /// <returns></returns>
    public ClassObjectPool<T> GetOrCreateClassPool<T>(int max) where T : class, new()
    {
      Type type = typeof(T);
      object outobj = null;
      if (!m_ClassPoolDic.TryGetValue(type, out outobj)|| outobj==null)
      {
            ClassObjectPool<T> pool = new ClassObjectPool<T>(max);
            m_ClassPoolDic.Add(type,pool);
            return pool;
      }
      return outobj as ClassObjectPool<T>;
    }


    /// <summary>
    /// 创建对象池且获取一个对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="maxcount"></param>
    /// <returns></returns>
    public T NewClassObjectFromPool<T>(int maxcount) where T : class, new()
    {
      ClassObjectPool<T> pool = new ClassObjectPool<T>(maxcount);
      if (pool == null) return null;
      return pool.Spwan(true);
    }

    #endregion
}
}
Orville's Ideas and Interestsusing System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace ABFrame
{

public class ObjectManager : Singleton<ObjectManager>
{
    /// <summary>
    /// 对象池节点
    /// </summary>
    protected Transform m_RecycleTs;
    /// <summary>
    /// 场景节点
    /// </summary>
    protected Transform m_SceneTs;

    /// <summary>
    /// 使用中的对象 对象池
    /// </summary>
    protected Dictionary<uint, List<ResourceObj>> m_ObjectPoolDic = new Dictionary<uint, List<ResourceObj>>();
    /// <summary>
    /// 暂存的Resourceobj Dic
    /// </summary>
    protected Dictionary<int, ResourceObj> m_RescourceObjDic = new Dictionary<int, ResourceObj>();
    /// <summary>
    /// ResourceObj 对象池
    /// </summary>
    protected ClassObjectPool<ResourceObj> m_ResourceObjPool = null;
    /// <summary>
    /// 根据异步的guid 存储ResourceObj 来判断是否时异步加载
    /// </summary>
    protected Dictionary<int, ResourceObj> m_AsyncResObjs = new Dictionary<int, ResourceObj>();

    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="recyclets"></param>
    public void Init(Transform recyclets,Transform scenets)
    {
      m_ResourceObjPool = ObjectManager.Instance.GetOrCreateClassPool<ResourceObj>( 500);
      this.m_RecycleTs = recyclets;
      this.m_RecycleTs.gameObject.SetActive(false);
      this.m_SceneTs = scenets;
    }




    /// <summary>
    /// 根据对象实例直接获取离线数据
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public OffLineData FindOffLineData(GameObject obj)
    {
      OffLineData offLineData = null;
      ResourceObj resobj = null;
      m_RescourceObjDic.TryGetValue(obj.GetInstanceID(),out resobj);
      if (resobj!=null)
      {
            offLineData = resobj.m_offLineData;
      }
      return offLineData;
    }


    /// <summary>
    /// 从对象池里面取对象
    /// </summary>
    /// <param name="path"></param>
    /// <param name="bclear"></param>
    /// <returns></returns>
    protected ResourceObj GetResourceObjFromPool(uint crc)
    {
      List<ResourceObj> list = null;
      if (this.m_ObjectPoolDic.TryGetValue(crc,out list)&&list!=null&&list.Count>0)
      {
            ///resourceManager 的引用计数
            ResourceManager.Instance.IncreaseResourceRef(crc);
            ResourceObj resourceObj = list;
            list.RemoveAt(0);
            GameObject obj = resourceObj.m_CloneObj;
            if (!System.Object.ReferenceEquals(obj,null))
            {
                if (!System.Object.ReferenceEquals(resourceObj.m_offLineData,null))
                {
                  resourceObj.m_offLineData.ResetPrpo();
                }
                resourceObj.m_Already = false;
#if UNITY_EDITOR
                if (obj.name.EndsWith("(Recycle)"))
                {
                  obj.name = obj.name.Replace("(Recycle)","");
                }
#endif
            }
            return resourceObj;
      }
      return null;
    }

    /// <summary>
    /// 取下异步加载
    /// </summary>
    public void CancelAsyncLoad(int guid)
    {
      ResourceObj resobj = null;
      if (m_AsyncResObjs.TryGetValue(guid,out resobj)&&ResourceManager.Instance.CancelAsyncLoad(resobj))
      {
            m_AsyncResObjs.Remove(guid);
            resobj.Reset();
            m_ResourceObjPool.Recycle(resobj);
      }
    }


    /// <summary>
    /// 是否正在异步加载
    /// </summary>
    /// <returns></returns>
    public bool IsAsyncLoading(int guid)
    {
      return m_AsyncResObjs.ContainsKey(guid);
    }


    /// <summary>
    /// 该对象是否是对象池创建的
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public bool IsObjectManangerCreate(GameObject obj)
    {
      int guid = obj.GetInstanceID();
      return m_RescourceObjDic.ContainsKey(guid);
    }



   

    /// <summary>
    /// 同步加载
    /// </summary>
    /// <param name="path"></param>
    /// <param name="bclear"></param>
    /// <returns></returns>
    public GameObject InstantiateObject(string path, bool isSceneObj=false,bool bclear = true)
    {
      uint crc = Crc32.GetCrc32(path);
      ResourceObj resourceObj = GetResourceObjFromPool(crc);
      if (resourceObj==null)
      {
            resourceObj = m_ResourceObjPool.Spwan(true);
            resourceObj.m_Crc = crc;
            resourceObj.m_bClear = bclear;
            //resourcemanager提供加载方法
            resourceObj= ResourceManager.Instance.LoadRecource(path, resourceObj);
            if (resourceObj.m_ResItem.m_Obj != null)
            {
                resourceObj.m_CloneObj = GameObject.Instantiate(resourceObj.m_ResItem.m_Obj) as GameObject;
                ///赋值离线加载数据
                resourceObj.m_offLineData = resourceObj.m_CloneObj.GetComponent<OffLineData>();
            }
      }
      if (isSceneObj) resourceObj.m_CloneObj.transform.SetParent(this.m_SceneTs, false);

      int tempId = resourceObj.m_CloneObj.GetInstanceID();
      if (!m_RescourceObjDic.ContainsKey(tempId))
            m_RescourceObjDic.Add(tempId,resourceObj);

      return resourceObj.m_CloneObj;
    }

    /// <summary>
    /// 异步资源加载
    /// </summary>
    /// <param name="path"></param>
    /// <param name="finishCallback">加载完成回调</param>
    /// <param name="loadResPriority"></param>
    /// <param name="isSceneObj"></param>
    /// <param name="param1"></param>
    /// <param name="param2"></param>
    /// <param name="param3"></param>
    /// <param name="bclear">跳场景是否删除</param>
    /// <returns></returns>
    public long InstantiateObjectAsync(string path, OnAsyncObjFinishDele finishCallback, LoadResPriority loadResPriority, bool isSceneObj = false, object param1 = null, object param2 = null, object param3 = null, bool bclear=true)
    {
      if (string.IsNullOrEmpty(path)) return 0;
      uint crc = Crc32.GetCrc32(path);
      ResourceObj obj = GetResourceObjFromPool(crc);
      if (obj!=null)
      {
            if (isSceneObj)
                obj.m_CloneObj.transform.SetParent(this.m_SceneTs,false);
            finishCallback?.Invoke(path, obj.m_CloneObj, param1, param2, param3);
            return obj.m_Guid;
      }

      int guid = ResourceManager.Instance.CreateGuid();
      obj = m_ResourceObjPool.Spwan(true);
      obj.m_Crc = crc;
      obj.m_bClear = bclear;
      obj.m_setSceneParent = isSceneObj;
      obj.m_FinishCallback = finishCallback;
      obj.m_Guid = guid;
      obj.Param1 = param1;
      obj.Param2 =param2;
      obj.Param3 = param3;

      //调用resourmanager 异步加载
      ResourceManager.Instance.AsnycLoadInstanceResource(path,obj, OnLoadInstanceObjFinish, loadResPriority,param1,param2,param3,crc);

      return guid;
    }

    /// <summary>
    ///当实例化资源加载完毕时的回调
    /// </summary>
    /// <param name="path">路径</param>
    /// <param name="obj">中间类</param>
    /// <param name="param1"></param>
    /// <param name="param2"></param>
    /// <param name="param3"></param>
    protected void OnLoadInstanceObjFinish(string path, ResourceObj resobj, object param1 = null, object param2 = null, object param3 = null)
    {
      if (resobj == null) return;
      if (resobj.m_ResItem.m_Obj==null)
      {
#if UNITY_EDITOR
            Debug.LogError("异步加载实例化资源错误:"+path);
#endif
      }
      else
      {
            resobj.m_CloneObj = GameObject.Instantiate(resobj.m_ResItem.m_Obj) as GameObject;
            ///赋值离线加载数据
            resobj.m_offLineData = resobj.m_CloneObj.GetComponent<OffLineData>();
      }
      if (resobj.m_CloneObj!=null&&resobj.m_setSceneParent)
      {
            resobj.m_CloneObj.transform.SetParent(this.m_SceneTs,false);
      }

      ///加载完成从正在加载的异步中移除
      if (m_AsyncResObjs.ContainsKey(resobj.m_Guid))
      {
            m_AsyncResObjs.Remove(resobj.m_Guid);
      }


      if (resobj.m_FinishCallback!=null)
      {
            int tempId = resobj.m_CloneObj.GetInstanceID();
            if (!m_RescourceObjDic.ContainsKey(tempId))
            {
                m_RescourceObjDic.Add(tempId,resobj);
            }
            resobj.m_FinishCallback(path,resobj.m_CloneObj,param1,param2,param3);
      }
    }

    /// <summary>
    ///回收资源
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="maxCacheCount"></param>
    /// <param name="destorycache"></param>
    /// <param name="recycleParent"></param>
    public void ReleaseObject(GameObject obj,int maxCacheCount=-1,bool destorycache=false,bool recycleParent=true)
    {
      if (obj == null) return;
      int guid = obj.GetInstanceID();

      ResourceObj resobj = null;
      if (!m_RescourceObjDic.TryGetValue(guid,out resobj))
      {
            Debug.LogError("对象不是ObjectManager 创建的" +obj.name);
            return;
      }

      if (resobj==null)
      {
            Debug.LogError("缓存的ResourceObj为空");
            return;
      }

      if (resobj.m_Already)
      {
            Debug.LogError("该对象已经放回对象池了 检查自己是否清空引用!");
            return;
      }

#if UNITY_EDITOR
      obj.name += "(Recycle)";
#endif
      List<ResourceObj> list = null;
      ///不缓存
      if (maxCacheCount==0)
      {
            m_RescourceObjDic.Remove(guid);
            ResourceManager.Instance.ReleaseResource(resobj,destorycache);
            resobj.Reset();
            m_ResourceObjPool.Recycle(resobj);
      }
      //回收到对象池
      else
      {
            if (!m_ObjectPoolDic.TryGetValue(resobj.m_Crc,out list)||list==null)
            {
                list = new List<ResourceObj>();
                m_ObjectPoolDic.Add(resobj.m_Crc,list);
            }
            if (resobj.m_CloneObj)
            {
                if (recycleParent)
                  resobj.m_CloneObj.transform.SetParent(this.m_RecycleTs);
                else
                  resobj.m_CloneObj.SetActive(false);
            }
            if (maxCacheCount < 0 ||list.Count < maxCacheCount)
            {
                list.Add(resobj);
                resobj.m_Already = true;
                //resourceManager 做一个引用计数
                ResourceManager.Instance.DecreaseResourceRef(resobj);
            }
            //达到最大缓存个数
            else
            {
                m_RescourceObjDic.Remove(guid);
                ResourceManager.Instance.ReleaseResource(resobj, destorycache);
                resobj.Reset();
                m_ResourceObjPool.Recycle(resobj);
            }
      }
    }



}
字数限制 不能发全部 需要的请移步码云
页: [1]
查看完整版本: Unity 资源加载框架(四) Assetbundle,音效等资源异步加载 ...