版权声明:未经允许不可转载 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