找回密码
 立即注册
查看: 270|回复: 0

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

[复制链接]
发表于 2023-3-1 13:57 | 显示全部楼层 |阅读模式
最近在写一本童话故事,欢迎点赞收藏,非常重要。给自己打个广告。以后会根据这本书开发一款游戏,文章有帮到你的话,请给书点个收藏。感谢。

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 Fail  path:" + path);
                return;
            }
            //当缓存达到最大数量时 清空缓存
            WashOut();
            if (obj == null)
                Debug.LogError("ResourceLoad Fail  path:" + 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.m_Crc] = 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[key];
            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[0];
            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[0];
            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);
            }
        }
    }



}
字数限制 不能发全部 需要的请移步码云
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-16 14:22 , Processed in 0.095223 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表