ObjectPoolManager功能
同步加载
异步加载
预加载
取消异步加载
基于离线数据的回收处理
ObjectPoolManager管理的资源和ResouceManager不一样,它的资源都是实例化(Clone)出来的,在游戏里真正显示的。
对象池同步加载 中间类ResouceObj 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class ResourceObj { public uint m_Crc = 0 ; public ResourceItem m_ResItem = null ; public GameObject m_CloneObj = null ; public bool m_bClear = true ; public long m_Guid = 0 ; public bool m_AlreadyReleased = false ; public void Reset () { m_Crc = 0 ; m_ResItem = null ; m_CloneObj = null ; m_bClear = true ; m_Guid = 0 ; m_AlreadyReleased = false ; } }
Resource Manager增加方法 在Resource Manager添加返回ResourceObj
的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public ResourceObj LoadResource (string path, ResourceObj resObj ) { if (resObj == null ) { return null ; } uint crc = resObj.m_Crc == 0 ?CRC32.GetCRC32(path) : resObj.m_Crc; ResourceItem item = GetCacheResourceItem(crc); if (item != null ) { resObj.m_ResItem = item; return resObj; } Object obj = null ; #if UNITY_EDITOR if (!m_LoadFromAssetBundle) { item = AssetBundleManager.Instance.FindResourceItem(resObj.m_Crc); if (item.m_Obj != null ) { obj = item.m_Obj; } else { obj = LoadAssetByEditor<Object>(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; } 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; }
对象池同步加载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 using System;using System.Collections.Generic;using UnityEngine;public class ObjectPoolManager :SingletonPattern <ObjectPoolManager >{ private Transform RecyclePoolTrans; public Transform SceneTrans; protected Dictionary<uint ,List<ResourceObj>> m_ObjectPoolDic = new Dictionary<uint , List<ResourceObj>>(); protected ClassObjectPool<ResourceObj> m_ResourceObjPool = null ; protected Dictionary<int ,ResourceObj> m_ResourceObjDic = new Dictionary<int ,ResourceObj>(); public void Init (Transform recyclePoolTrans,Transform sceneTrans ) { m_ResourceObjPool = GetOrCreatClassPool<ResourceObj>(1000 ); RecyclePoolTrans = recyclePoolTrans; SceneTrans = sceneTrans; } protected ResourceObj GetObjectFromDicCache (uint crc ) { List<ResourceObj> resObjList = null ; if (m_ObjectPoolDic.TryGetValue(crc, out resObjList) && resObjList != null && resObjList.Count>0 ) { ResourceManager.Instance.IncreaseResourceRef(crc); ResourceObj resObj = resObjList[0 ]; resObjList.RemoveAt(0 ); GameObject obj = resObj.m_CloneObj; if (!System.Object.ReferenceEquals(obj, null )) { #if UNITY_EDITOR if (obj.name.EndsWith("(Recycle)" )) { obj.name = obj.name.Replace("(Recycle)" , "" ); } #endif } return resObj; } return null ; } public GameObject InstantiateObject (string path,bool setSceneObj = false , bool bClear = true ) { uint crc = CRC32.GetCRC32(path); ResourceObj resourceObj = GetObjectFromDicCache(crc); if (resourceObj == null ) { resourceObj = m_ResourceObjPool.Spawn(true ); resourceObj.m_Crc = crc; resourceObj.m_bClear = bClear; resourceObj = ResourceManager.Instance.LoadResource(path, resourceObj); if (resourceObj.m_ResItem.m_Obj != null ) { resourceObj.m_CloneObj = GameObject.Instantiate(resourceObj.m_ResItem.m_Obj) as GameObject; } } if (setSceneObj) { resourceObj.m_CloneObj.transform.SetParent(SceneTrans,false ); } int tempGUID = resourceObj.m_CloneObj.GetInstanceID(); if (!m_ResourceObjDic.ContainsKey(tempGUID)) { m_ResourceObjDic.Add(tempGUID, resourceObj); } return resourceObj.m_CloneObj; } #region 类对象池的使用 protected Dictionary<Type, object > m_ClassPoolDic = new Dictionary<Type, object >(); public ClassObjectPool <T > GetOrCreatClassPool <T >(int maxCount ) where T : class , new () { Type type = typeof (T); object outObj = null ; if (!m_ClassPoolDic.TryGetValue(type, out outObj) || outObj == null ) { ClassObjectPool<T> newPool = new ClassObjectPool<T>(maxCount); m_ClassPoolDic.Add(type, newPool); return newPool; } return outObj as ClassObjectPool<T>; } #endregion }
对象池资源释放 先在Resource Manager中添加为对象池释放资源的API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public bool ReleaseResource (ResourceObj resObj, bool destroyObj = false ){ if (resObj == null ) return false ; ResourceItem item = null ; if (!AssetDic.TryGetValue(resObj.m_Crc, out item) || item == null ) { Debug.LogError("AssetDic里不存在该资源:" + resObj.m_CloneObj.name + "可能释放了多次" ); } GameObject.Destroy(resObj.m_CloneObj.gameObject); item.RefCount--; DestroyResourceItem(item, destroyObj); return true ; }
再在ObjectPool Manager中添加回收对象的API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public void ReleaseObject (GameObject obj, int maxCacheCount = -1 , bool destroyCache = false , bool hasRecycleParent = true ) { if (obj == null ) { return ; } ResourceObj resObj = null ; int tempGUID = obj.GetInstanceID(); if (!m_ResourceObjDic.TryGetValue(tempGUID, out resObj)) { Debug.Log(obj.name + "对象可能不是由对象池创建" ); return ; } if (resObj == null ) { Debug.LogError("缓存的ResourceObj为空" ); } if (resObj.m_AlreadyReleased) { Debug.LogError("此对象已经放回对象池,请检查是否清空引用" ); return ; } #if UNITY_EDITOR obj.name += "(Recycle)" ; #endif List<ResourceObj> list = null ; if (maxCacheCount == 0 ) { m_ResourceObjDic.Remove(tempGUID); ResourceManager.Instance.ReleaseResource(resObj, destroyCache); 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 != null ) { if (hasRecycleParent) { resObj.m_CloneObj.transform.SetParent(RecyclePoolTrans); } else { resObj.m_CloneObj.SetActive(false ); } } if (maxCacheCount < 0 || list.Count < maxCacheCount) { list.Add(resObj); resObj.m_AlreadyReleased = true ; ResourceManager.Instance.DecreaseResourceRef(resObj); } else { m_ResourceObjDic.Remove(tempGUID); ResourceManager.Instance.ReleaseResource(resObj, destroyCache); resObj.Reset(); m_ResourceObjPool.Recycle(resObj); } } }
对象池引用计数 我们在Object Pool Manager第一次引用Resource Manager的资源时,Resource Manager会生成ResourceItem
中间类供ResourceObj
中间类引用,此时ResourceItem
中间类会增加一个引用计数。而我们使用Object Pool Manager再次取用Object时,由于我们已经缓存了生成的Object,这一引用计数就不会再增加了,我们需要在ResourceManager
添加增加和减少引用计数的API。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public int IncreaseResourceRef (ResourceObj resObj,int refCount = 1 ){ return resObj != null ? IncreaseResourceRef(resObj.m_Crc, refCount) : 0 ; } public int IncreaseResourceRef (uint crc = 0 , int refCount = 1 ){ ResourceItem item = null ; if (!AssetDic.TryGetValue(crc, out item) || item == null ) { return 0 ; } item.RefCount += refCount; item.m_LastUseTime = Time.realtimeSinceStartup; return item.RefCount; } public int DecreaseResourceRef (ResourceObj resObj, int refCount = 1 ){ return resObj != null ? DecreaseResourceRef(resObj.m_Crc, refCount) : 0 ; } public int DecreaseResourceRef (uint crc, int refCount = 1 ){ ResourceItem item = null ; if (!AssetDic.TryGetValue(crc, out item) || item == null ) { return 0 ; } item.RefCount -= refCount; return item.RefCount; }
接着在Object Pool Manager的GetObjectFromDicCache
方法体内调用
1 2 3 4 5 6 7 8 9 10 protected ResourceObj GetObjectFromDicCache (uint crc ){ List<ResourceObj> resObjList = null ; if (m_ObjectPoolDic.TryGetValue(crc, out resObjList) && resObjList != null && resObjList.Count>0 ) { ResourceManager.Instance.IncreaseResourceRef(crc); } }
在Object Pool Manager的ReleaseObject
方法体内调用
1 2 3 4 5 6 7 8 9 if (maxCacheCount < 0 || list.Count < maxCacheCount) { list.Add(resObj); resObj.m_AlreadyReleased = true ; ResourceManager.Instance.DecreaseResourceRef(resObj); }
此ResourceObj
对应的ResourceItem
的引用计数减少了,但ResourceObj
在Object Pool Manger中的m_ResourceObjDic
依然缓存着
我们只有在对象池内部 进行对象的增加和回收操作时才会调用IncreaseResourceRef
和DecreaseResourceRef
方法,其他的操作就像直接在Resource Manager取用资源一样,不用再多余维护ResourceItem的引用计数。
同步资源加载示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 using UnityEngine;public class GameStart : MonoBehaviour { private GameObject m_GameObject; private void Awake () { DontDestroyOnLoad(gameObject); AssetBundleManager.Instance.LoadAssetBundleConfig(); ResourceManager.Instance.Init(this ); ObjectPoolManager.Instance.Init(transform.Find("RecyclePoolTrans" ),transform.Find("SceneTrans" )); } private void Start () { m_GameObject = ObjectPoolManager.Instance.InstantiateObject("Assets/Prefabs/Attack.prefab" ,true ); } private void Update () { if (Input.GetKeyDown(KeyCode.A)) { ObjectPoolManager.Instance.ReleaseObject(m_GameObject); m_GameObject = null ; } else if (Input.GetKeyDown(KeyCode.D)) { m_GameObject = ObjectPoolManager.Instance.InstantiateObject("Assets/Prefabs/Attack.prefab" , true ); } else if (Input.GetKeyDown(KeyCode.S)) { ObjectPoolManager.Instance.ReleaseObject(m_GameObject, 0 , true ); m_GameObject = null ; } } private void OnApplicationQuit () { ResourceManager.Instance.ClearCache(); Resources.UnloadUnusedAssets(); } }