unity 商业游戏底层资源管理加载框架——个人学习记录(9)

版权声明:未经允许不可转载 https://blog.csdn.net/Edision_li/article/details/90078261

基础资源同步加载

思路 : 根据之前打包所在的路径获取CRC,根据CRC获取中间类ResouceItem(单个资源对应的中间类,哪怕prefabs依赖的资源也是单个对应一个ResouceItem)

using System.Collections.Generic;
using UnityEngine;

/*使用双向链表的原因 : 资源的使用频率,如果资源频繁使用,希望其处于最顶端.
* 不使用的慢慢放在底端去,清理缓存的时候从底端开始清理*/
public class ResourceManager : Singleton<ResourceManager>
{
    public bool m_IsLoadFromAssetBundle = false;
    /// <summary>
    /// 缓存使用的资源列表
    /// </summary>
    private Dictionary<uint, ResourceItem> assetDict;
    public Dictionary<uint, ResourceItem> AssetDict
    {
        get
        {
            if (assetDict == null)
            {
                assetDict = new Dictionary<uint, ResourceItem>();
            }
            return assetDict;
        }

        set { }
    }
    /// <summary>
    /// 缓存引用计数为零的资源列表,达到缓存最大的时候释放这个列表里最早没用的资源
    /// </summary>
    protected CMapList<ResourceItem> m_NoRefrenceAssetMapList = new CMapList<ResourceItem>();



    /// <summary>
    /// 同步资源加载,外部直接调用,仅仅加载不需要实例化的资源,例如:texture,audioclip
    /// </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 = GetCacheResourceItem(crc);
        if (item != null)
        {
            return item.m_Obj as T;
        }
        T obj = null;
#if UNITY_EDITOR
        if (!m_IsLoadFromAssetBundle)
        {
            item = AssetBundleManager.Instance.FindResourceItem(crc);
            if (item != null && item.m_AssetBundle != null)
            {
                if (item.m_Obj != null)
                {
                    obj = item.m_Obj as T;
                }
                else
                {
                    obj = LoadByEditor<T>(item.m_AssetName);
                }
            }
            else
            {
                if (item == null)
                {
                    item = new ResourceItem();
                    item.m_Crc = crc;
                }
                obj = LoadByEditor<T>(path);
            }

        }
#endif
        if (obj == null)
        {
            item = AssetBundleManager.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>
    /// 不需要实例化的资源卸载
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="isDestroyObj"></param>
    /// <returns></returns>
    public bool ReleaseResource(Object obj, bool isDestroyObj = false)
    {
        if (obj == null)
        {
            return false;
        }
        ResourceItem item = null;
        foreach (ResourceItem res in AssetDict.Values)
        {
            if (res.m_Guid == obj.GetInstanceID())
            {
                item = res;
            }
        }
        if (item == null)
        {
            Debug.LogError("AssetDict 中不存在该资源:" + obj.name + "  可能释放了多次");
            return false;
        }
        item.RefCount--;
        DestroyResourceItem(item, isDestroyObj);
        return true;
    }
    /// <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)
    {
        //缓存太多,清除最早没有使用的资源
        WashOut();
        if (item == null)
        {
            Debug.LogError("ResourceItem is null,Path :" + path);
        }
        if (obj == null)
        {
            Debug.LogError("ResourceLoad Fail :" + path);
        }
        item.m_Obj = obj;
        item.m_Guid = obj.GetInstanceID();
        item.m_LastUseTime = Time.realtimeSinceStartup;
        item.RefCount += addRefCount;
        ResourceItem oldItem = null;
        if (AssetDict.TryGetValue(item.m_Crc, out oldItem))
        {
            AssetDict[item.m_Crc] = item;
        }
        else
        {
            AssetDict.Add(crc, item);
        }
    }
    /// <summary>
    /// 缓存太多,清除最早没有使用的资源
    /// </summary>
    protected void WashOut()
    {
        ////当 当前内从使用大于百分之八十后清除清除最早没有使用的资源
        //{
        //    if (m_NoRefrenceAssetMapList.Size()<=0)
        //    {
        //        break;

        //        ResourceItem item = m_NoRefrenceAssetMapList.Back();
        //        DestroyResourceItem(item, true);
        //        m_NoRefrenceAssetMapList.Pop();
        //    }
        //}
        //当大于缓存个数时,进行一半释放


    }
    /// <summary>
    /// 回收一个资源
    /// </summary>
    /// <param name="item"></param>
    /// <param name="isDestroy"></param>
    protected void DestroyResourceItem(ResourceItem item, bool isDestroyCache = false)
    {
        if (item == null || item.RefCount > 0)
        {
            return;
        }
        if (!AssetDict.Remove(item.m_Crc))
        {
            return;
        }
        if (!isDestroyCache)
        {
            m_NoRefrenceAssetMapList.InsertToHead(item);
            return;
        }
        m_NoRefrenceAssetMapList.Remove(item);

        //释放aseetbundle  引用
        AssetBundleManager.Instance.ReleaseAsset(item);
        if (item.m_Obj != null)
        {
            item.m_Obj = null;
        }
    }
#if UNITY_EDITOR
    protected T LoadByEditor<T>(string path) where T : UnityEngine.Object
    {
        return UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path);
    }
#endif
    ResourceItem GetCacheResourceItem(uint crc, int addRefCount = 1)
    {
        ResourceItem item = null;

        if (AssetDict.TryGetValue(crc, out item))
        {
            if (item != null)
            {
                item.RefCount += addRefCount;
                item.m_LastUseTime = Time.realtimeSinceStartup;

                if (item.RefCount <= 1)
                {
                    m_NoRefrenceAssetMapList.Remove(item);
                }
            }
        }
        return item;
    }
}

/// <summary>
/// 双向链表的结构节点
/// </summary>
/// <typeparam name="T"></typeparam>
public class DoubleLinkedListNode<T> where T : class
{
    /// <summary>
    /// 前一个节点
    /// </summary>
    public DoubleLinkedListNode<T> prev = null;
    /// <summary>
    /// 后一个节点
    /// </summary>
    public DoubleLinkedListNode<T> next = null;
    /// <summary>
    /// 当前节点
    /// </summary>
    public T t = null;
}

/// <summary>
/// 双向链表结构
/// </summary>
/// <typeparam name="T"></typeparam>
public class DoubleLinkedList<T> where T : class, new()
{
    /// <summary>
    /// 表头
    /// </summary>
    public DoubleLinkedListNode<T> Head = null;
    /// <summary>
    /// 表尾
    /// </summary>
    public DoubleLinkedListNode<T> Tail = null;
    /// <summary>
    /// 双向链表结构类对象池
    /// </summary>
    protected ClassObjectPool<DoubleLinkedListNode<T>> m_DoubleLinkedNodePool = ObjectManager.Instance.GetOrCreateClassPool<DoubleLinkedListNode<T>>(500);
    /// <summary>
    /// 个数
    /// </summary>
    protected int m_Count = 0;

    public int Count { get { return m_Count; } }

    /// <summary>
    /// 添加一个节点到头部
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public DoubleLinkedListNode<T> AddToHeader(T t)
    {
        DoubleLinkedListNode<T> pList = m_DoubleLinkedNodePool.Spawn(true);
        pList.prev = null;
        pList.next = null;
        pList.t = t;
        return AddToHeader(pList);
    }
    /// <summary>
    /// 添加一个节点到头部
    /// </summary>
    /// <param name="pNode"></param>
    /// <returns></returns>
    public DoubleLinkedListNode<T> AddToHeader(DoubleLinkedListNode<T> pNode)
    {
        if (pNode == null)
        {
            return null;
        }
        pNode.prev = null;
        if (Head == null)
        {
            Head = Tail = pNode;
        }
        else
        {
            pNode.next = Head;
            Head.prev = pNode;
            Head = pNode;
        }
        m_Count++;
        return Head;
    }
    /// <summary>
    /// 添加节点到尾部
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public DoubleLinkedListNode<T> AddToTail(T t)
    {
        DoubleLinkedListNode<T> pList = m_DoubleLinkedNodePool.Spawn(true);
        pList.prev = null;
        pList.next = null;
        pList.t = t;
        return AddToTail(pList);
    }
    /// <summary>
    /// 添加节点到尾部
    /// </summary>
    /// <param name="pNode"></param>
    /// <returns></returns>
    public DoubleLinkedListNode<T> AddToTail(DoubleLinkedListNode<T> pNode)
    {
        if (pNode == null)
        {
            return null;
        }
        pNode.next = null;
        if (Tail == null)
        {
            Head = Tail = pNode;
        }
        else
        {
            pNode.prev = Tail;
            Tail.next = pNode;
            Tail = pNode;
        }
        m_Count++;
        return Tail;
    }
    /// <summary>
    /// 移除某个节点
    /// </summary>
    /// <param name="pNode"></param>
    public void RemoveNode(DoubleLinkedListNode<T> pNode)
    {
        if (pNode == null)
        {
            return;
        }
        if (pNode == Head)
        {
            Head = pNode.next;
        }
        if (pNode == Tail)
        {
            Tail = pNode.prev;
        }
        if (pNode.prev != null)
        {
            pNode.prev.next = pNode.next;
        }
        if (pNode.next != null)
        {
            pNode.next.prev = pNode.prev;
        }
        pNode.next = pNode.prev = null;
        pNode.t = null;
        m_DoubleLinkedNodePool.Recycle(pNode);
        m_Count--;
    }
    /// <summary>
    /// 移动到头部
    /// </summary>
    /// <param name="pNode"></param>
    public void MoveToHead(DoubleLinkedListNode<T> pNode)
    {
        if (pNode == null || pNode == Head)
        {
            return;
        }
        if (pNode.next == null && pNode.prev == null)
        {
            return;
        }
        if (pNode == Tail)
        {
            Tail = pNode.prev;
        }
        if (pNode.prev != null)
        {
            pNode.prev.next = pNode.next;
        }
        if (pNode.next != null)
        {
            pNode.next.prev = pNode.prev;
        }

        pNode.prev = null;
        pNode.next = Head;
        Head.prev = pNode;
        Head = pNode;
        if (Tail == null)
        {
            Tail = Head;
        }
    }
}

/// <summary>
/// 对其简单的封装(一般包括插入,查找,获取表头,获取表尾,清除,移除,获取长度等):
/// </summary>
/// <typeparam name="T"></typeparam>
public class CMapList<T> where T : class, new()
{
    DoubleLinkedList<T> m_DLink = new DoubleLinkedList<T>();

    Dictionary<T, DoubleLinkedListNode<T>> m_FindMapDict = new Dictionary<T, DoubleLinkedListNode<T>>();
    /// <summary>
    /// 析构函数
    /// </summary>
    ~CMapList()
    {
        Clear();
    }

    /// <summary>
    /// 清除列表
    /// </summary>
    public void Clear()
    {
        while (m_DLink.Tail != null)
        {
            Remove(m_DLink.Tail.t);
        }

    }
    /// <summary>
    /// 插入一个节点到表头
    /// </summary>
    /// <param name="t"></param>
    public void InsertToHead(T t)
    {
        DoubleLinkedListNode<T> node = null;
        if (m_FindMapDict.TryGetValue(t, out node) && node != null)
        {
            m_DLink.AddToHeader(node);
            return;
        }
        m_DLink.AddToHeader(t);
        m_FindMapDict.Add(t, m_DLink.Head);
    }
    /// <summary>
    /// 从表尾弹出一个节点
    /// </summary>
    public void Pop()
    {
        if (m_DLink.Tail != null)
        {
            Remove(m_DLink.Tail.t);
        }

    }
    /// <summary>
    /// 删除某个节点
    /// </summary>
    /// <param name="t"></param>
    public void Remove(T t)
    {
        DoubleLinkedListNode<T> node = null;
        if (!m_FindMapDict.TryGetValue(t, out node) || node == null)
        {
            return;
        }
        m_DLink.RemoveNode(node);
        m_FindMapDict.Remove(t);
    }
    /// <summary>
    /// 获取到尾部节点
    /// </summary>
    public T Back()
    {
        return m_DLink.Tail == null ? null : m_DLink.Tail.t;
    }
    /// <summary>
    /// 返回节点个数
    /// </summary>
    /// <returns></returns>
    public int Size()
    {
        return m_FindMapDict.Count;
    }
    /// <summary>
    /// 查找是否存在该节点
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public bool Find(T t)
    {
        DoubleLinkedListNode<T> node = null;
        if (!m_FindMapDict.TryGetValue(t, out node) || node == null)
        {
            return false;
        }

        return true;
    }
    /// <summary>
    /// 刷新某个节点,把节点移动到头部
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public bool Refresh(T t)
    {
        DoubleLinkedListNode<T> node = null;
        if (!m_FindMapDict.TryGetValue(t, out node) || node == null)
        {
            return false;
        }
        m_DLink.RemoveNode(node);
        return true;
    }
}

测试

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

public class TestPool : MonoBehaviour
{

    public AudioSource m_AS;
    private AudioClip m_AC;
    // Use this for initialization
    void Start()
    {
        Debug.Log("#####开始测试......");
    }

    // Update is called once per frame
    void Update()
    {
        /*
         * public class ResourceManager : Singleton<ResourceManager>中
            public bool m_IsLoadFromAssetBundle = true;
            则先左键,后右键
         */
        if (Input.GetMouseButtonDown(0))
        {
            Debug.Log(AssetBundleManager.Instance.LoadAssetBundleConfig());
        }
        if (Input.GetMouseButtonDown(1))
        {
            m_AC = ResourceManager.Instance.LoadResource<AudioClip>("Assets/FoxPackage/Sounds/die.ogg");
            m_AS.clip = m_AC;
            m_AS.Play();
        }
        if (Input.GetMouseButtonDown(2))
        {
            m_AS.Stop();
            m_AS.clip = null;
            ResourceManager.Instance.ReleaseResource(m_AC);
            m_AC = null;
        }
    }
}

四.基础资源异步加载

思路 : 首先判断资源是否已经加载,如果已经加载,调用加载完成函数,如果未加载,判断是否正在加载资源

end

猜你喜欢

转载自blog.csdn.net/Edision_li/article/details/90078261