再谈对象池及扩展通用性
发表于2018-10-20
最近做一款音乐游戏,需要显示较多的音符,需频繁回收利用GameObject,简易的对象池满足不了需求,以前写过一个对象池 对象池(重复资源的循环利用)_008 , 使用起来有比较有局限性,不是很方便,就考虑写一个通用的对象池,可以适用于各种项目类型,而且调用要简便。参考了一些资料,并利用This添加了静态方法,方便调用,就此有了万能对象池~(大佬们看见不要打我 ···)
调用,对~ 就是这么简单,prefab可以是GameObject,也可以是任意组件、自定义的类,适用于各种情况。
使用前只需要创建一个池,加载对象到场景时调用创建方法,销毁时调用回收方法即可~~
void Test() { //创建对象池 prefab.CreatePool(); //生成池对象 prefab.Create(); //回收池对象 prefab.Reset(); }
对象池部分,代码比较简单,不多说
public sealed class GenericPool : MonoBehaviour { //预加载对象池启动方式 public enum StartupPoolMode { Awake, Start, Manual }; [System.Serializable] public class StartupPool { public GameObject prefab; public int size; } // ---------- static List<GameObject> tempList = new List<GameObject>(); //池内对象<prefab, list<obj>> 经过实测, List效率比Queue高 Dictionary<GameObject, List<GameObject>> idlePoolDic = new Dictionary<GameObject, List<GameObject>>(); //池外对象<obj, prefab> Dictionary<GameObject, GameObject> workItemDic = new Dictionary<GameObject, GameObject>(); //池对象父物体<prefab, parentTrans> Dictionary<GameObject, Transform> poolParentDic = new Dictionary<GameObject, Transform>(); //开启方式 [SerializeField, Header("对象池启动方式")] StartupPoolMode startupPoolMode; [SerializeField, Header("预加载对象池")] StartupPool[] startupPools; //单例 static GenericPool instanse; public static GenericPool Instanse { get { if (instanse != null) return instanse; instanse = FindObjectOfType<GenericPool>(); if (instanse != null) return instanse; GameObject obj = new GameObject("ObjectPool"); obj.transform.position = Vector3.zero; instanse = obj.AddComponent<GenericPool>(); return instanse; } } void Awake() { if (instanse == null) instanse = this; else if (instanse != this) DestroyImmediate(gameObject); if (startupPoolMode == StartupPoolMode.Awake) StartupPools(); } void Start() { if (startupPoolMode == StartupPoolMode.Start) StartupPools(); } //是否已开启pools, 保证只执行一次 bool isStartup; public void StartupPools() { if (isStartup) { isStartup = true; if (startupPools != null && startupPools.Length > 0) for (int i = 0; i < startupPools.Length; i++) CreatePool(startupPools[i].prefab, startupPools[i].size); } } // ----- 创建对象池 ----- public static bool CreatePool<T>(T prefab, int initialPoolSize) where T : Component { return CreatePool(prefab.gameObject, initialPoolSize); } public static bool CreatePool(GameObject prefab, int initialPoolSize) { if (prefab != null && !Instanse.idlePoolDic.ContainsKey(prefab)) { List<GameObject> list = new List<GameObject>(); //创建父节点 Transform poolParent = new GameObject("Pool_" + prefab.name).transform; poolParent.gameObject.SetActive(false); poolParent.SetParent(Instanse.transform); Instanse.poolParentDic.Add(prefab, poolParent); if (initialPoolSize > 0) { for (int i = 0; i < initialPoolSize; i++) { GameObject obj = Instantiate(prefab); obj.transform.SetParent(poolParent); list.Add(obj); } } Instanse.idlePoolDic.Add(prefab, list); return true; } return false; } // ----- 获取池对象 ----- public static T Create<T>(T prefab) where T : Component { return Create(prefab.gameObject, null, Vector3.zero, Quaternion.identity).GetComponent<T>(); } public static T Create<T>(T prefab, Transform parent) where T : Component { return Create(prefab.gameObject, parent, Vector3.zero, Quaternion.identity).GetComponent<T>(); } public static T Create<T>(T prefab, Vector3 position) where T : Component { return Create(prefab.gameObject, null, position, Quaternion.identity).GetComponent<T>(); } public static T Create<T>(T prefab, Transform parent, Vector3 position) where T : Component { return Create(prefab.gameObject, parent, position, Quaternion.identity).GetComponent<T>(); } public static T Create<T>(T prefab, Vector3 position, Quaternion rotation) where T : Component { return Create(prefab.gameObject, null, position, rotation).GetComponent<T>(); } public static T Create<T>(T prefab, Transform parent, Vector3 position, Quaternion rotation) where T : Component { return Create(prefab.gameObject, parent, position, rotation).GetComponent<T>(); } public static GameObject Create(GameObject prefab) { return Create(prefab, null, Vector3.zero, Quaternion.identity); } public static GameObject Create(GameObject prefab, Transform parent) { return Create(prefab, parent, Vector3.zero, Quaternion.identity); } public static GameObject Create(GameObject prefab, Vector3 position) { return Create(prefab, null, position, Quaternion.identity); } public static GameObject Create(GameObject prefab, Transform parent, Vector3 position) { return Create(prefab, parent, position, Quaternion.identity); } public static GameObject Create(GameObject prefab, Vector3 position, Quaternion rotation) { return Create(prefab, null, position, rotation); } public static GameObject Create(GameObject prefab, Transform parent, Vector3 position, Quaternion rotation) { List<GameObject> list; GameObject obj; if (Instanse.idlePoolDic.TryGetValue(prefab, out list)) { obj = null; if (list.Count > 0) { while (obj == null && list.Count > 0) { obj = list[0]; list.RemoveAt(0); } if (obj != null) { SetObjParame(obj, parent, position, rotation); Instanse.workItemDic.Add(obj, prefab); return obj; } } obj = Instantiate(prefab); SetObjParame(obj, parent, position, rotation); Instanse.workItemDic.Add(obj, prefab); return obj; } //不在对象池内 obj = Instantiate(prefab); SetObjParame(obj, parent, position, rotation); return obj; } static void SetObjParame(GameObject obj, Transform parent, Vector3 position, Quaternion rotation) { obj.transform.SetParent(parent); obj.transform.localPosition = position; obj.transform.localRotation = rotation; } // ----- 回收池对象 ----- public static void Reset<T>(T obj) where T : Component { Reset(obj.gameObject); } public static void Reset(GameObject obj) { GameObject prefab; //在池内, 回收, 不在则销毁 if (Instanse.workItemDic.TryGetValue(obj, out prefab)) Reset(obj, prefab); else Destroy(obj); } static void Reset(GameObject obj, GameObject prefab) { Instanse.idlePoolDic[prefab].Add(obj); Instanse.workItemDic.Remove(obj); obj.transform.SetParent(Instanse.poolParentDic[prefab]); } public static void ResetAll<T>(T prefab) where T : Component { ResetAll(prefab.gameObject); } public static void ResetAll(GameObject prefab) { foreach (var item in Instanse.workItemDic) { if (item.Value == prefab) tempList.Add(item.Key); } for (int i = 0; i < tempList.Count; ++i) { Reset(tempList[i], prefab); } tempList.Clear(); } public static void ResetAll() { tempList.AddRange(Instanse.workItemDic.Keys); for (int i = 0; i < tempList.Count; ++i) { Reset(tempList[i]); } tempList.Clear(); } // ----- 销毁对象池 ----- public static void DestroyPoolIdle<T>(T prefab) where T : Component { DestroyPoolIdle(prefab.gameObject); } public static void DestroyPoolIdle(GameObject prefab) { List<GameObject> pool; if (Instanse.idlePoolDic.TryGetValue(prefab, out pool)) { for (int i = 0; i < pool.Count; ++i) { Destroy(pool[i]); } pool.Clear(); } } public static void DestroyPoolAll<T>(T prefab) where T : Component { DestroyPoolAll(prefab.gameObject); } public static void DestroyPoolAll(GameObject prefab) { ResetAll(prefab); DestroyPoolIdle(prefab); Destroy(Instanse.poolParentDic[prefab]); Instanse.poolParentDic.Remove(prefab); } // ----- 获取池状态 ----- //是否已创建池 public static bool IsCreatPool<T>(T prefab) where T : Component { return IsCreatPool(prefab.gameObject); } public static bool IsCreatPool(GameObject prefab) { return Instanse.idlePoolDic.ContainsKey(prefab); } //是否在对象池内 public static bool IsInPool<T>(T obj) where T : Component { return IsInPool(obj.gameObject); } public static bool IsInPool(GameObject obj) { return Instanse.workItemDic.ContainsKey(obj); } //池内对象数量 public static int PoolIdleCount<T>(T prefab) where T : Component { return PoolIdleCount(prefab.gameObject); } public static int PoolIdleCount(GameObject prefab) { List<GameObject> list; if (Instanse.idlePoolDic.TryGetValue(prefab, out list)) return list.Count; return 0; } //池外对象数量 public static int PoolWorkCount<T>(T prefab) where T : Component { return PoolWorkCount(prefab.gameObject); } public static int PoolWorkCount(GameObject prefab) { int count = 0; foreach (var InstansePrefab in Instanse.workItemDic.Values) if (prefab == InstansePrefab) count++; return count; } //所有池内对象数量总和 public static int AllPoolIdleCount() { int count = 0; foreach (List<GameObject> list in Instanse.idlePoolDic.Values) count += list.Count; return count; } //所有池外对象数量总和 public static int AllPoolWorkCount() { return Instanse.workItemDic.Count; } // ----- //获取池内所有对象 public static List<T> GetPoolIdleItem<T>(T prefab, List<T> list = null, bool appendList = true) where T : Component { if (list == null) list = new List<T>(); if (!appendList) list.Clear(); List<GameObject> pool; if (Instanse.idlePoolDic.TryGetValue(prefab.gameObject, out pool)) for (int i = 0; i < pool.Count; ++i) list.Add(pool[i].GetComponent<T>()); return list; } public static List<GameObject> GetPoolIdleItem(GameObject prefab, List<GameObject> list = null, bool appendList = true) { if (list == null) list = new List<GameObject>(); if (!appendList) list.Clear(); List<GameObject> pool; if (Instanse.idlePoolDic.TryGetValue(prefab, out pool)) list.AddRange(pool); return list; } //获取池外所有对象 public static List<T> GetPoolWorkItem<T>(T prefab, List<T> list = null, bool appendList = true) where T : Component { if (list == null) list = new List<T>(); if (!appendList) list.Clear(); var prefabObj = prefab.gameObject; foreach (var item in Instanse.workItemDic) if (item.Value == prefabObj) list.Add(item.Key.GetComponent<T>()); return list; } public static List<GameObject> GetPoolWorkItem(GameObject prefab, List<GameObject> list = null, bool appendList = true) { if (list == null) list = new List<GameObject>(); if (!appendList) list.Clear(); foreach (var item in Instanse.workItemDic) if (item.Value == prefab) list.Add(item.Key); return list; } }
利用This再封装,这一部分都是重复代码,可忽略,目的就是将对象池的方法,利用This进行静态封装,方便使用时调用。
public static class GenericPoolHelper { public static void CreatePool<T>(this T prefab, int initialPoolSize = 0) where T : Component { GenericPool.CreatePool(prefab, initialPoolSize); } public static void CreatePool(this GameObject prefab, int initialPoolSize = 0) { GenericPool.CreatePool(prefab, initialPoolSize); } public static T Create<T>(this T prefab) where T : Component { return GenericPool.Create(prefab, null, Vector3.zero, Quaternion.identity); } public static T Create<T>(this T prefab, Transform parent) where T : Component { return GenericPool.Create(prefab, parent, Vector3.zero, Quaternion.identity); } public static T Create<T>(this T prefab, Vector3 position) where T : Component { return GenericPool.Create(prefab, null, position, Quaternion.identity); } public static T Create<T>(this T prefab, Transform parent, Vector3 position) where T : Component { return GenericPool.Create(prefab, parent, position, Quaternion.identity); } public static T Create<T>(this T prefab, Vector3 position, Quaternion rotation) where T : Component { return GenericPool.Create(prefab, null, position, rotation); } public static T Create<T>(this T prefab, Transform parent, Vector3 position, Quaternion rotation) where T : Component { return GenericPool.Create(prefab, parent, position, rotation); } public static GameObject Create(this GameObject prefab) { return GenericPool.Create(prefab, null, Vector3.zero, Quaternion.identity); } public static GameObject Create(this GameObject prefab, Transform parent) { return GenericPool.Create(prefab, parent, Vector3.zero, Quaternion.identity); } public static GameObject Create(this GameObject prefab, Vector3 position) { return GenericPool.Create(prefab, null, position, Quaternion.identity); } public static GameObject Create(this GameObject prefab, Transform parent, Vector3 position) { return GenericPool.Create(prefab, parent, position, Quaternion.identity); } public static GameObject Create(this GameObject prefab, Vector3 position, Quaternion rotation) { return GenericPool.Create(prefab, null, position, rotation); } public static GameObject Create(this GameObject prefab, Transform parent, Vector3 position, Quaternion rotation) { return GenericPool.Create(prefab, parent, position, rotation); } public static void Reset<T>(this T obj) where T : Component { GenericPool.Reset(obj); } public static void Reset(this GameObject obj) { GenericPool.Reset(obj); } public static void ResetAll<T>(this T prefab) where T : Component { GenericPool.ResetAll(prefab); } public static void ResetAll(this GameObject prefab) { GenericPool.ResetAll(prefab); } public static void DestroyPoolIdle<T>(this T prefab) where T : Component { GenericPool.DestroyPoolIdle(prefab); } public static void DestroyPoolIdle(this GameObject prefab) { GenericPool.DestroyPoolIdle(prefab); } public static void DestroyPoolAll<T>(this T prefab) where T : Component { GenericPool.DestroyPoolAll(prefab); } public static void DestroyPoolAll(this GameObject prefab) { GenericPool.DestroyPoolAll(prefab); } public static bool IsCreatPool<T>(this T prefab) where T : Component { return GenericPool.IsCreatPool(prefab); } public static bool IsCreatPool(this GameObject prefab) { return GenericPool.IsCreatPool(prefab); } public static bool IsInPool<T>(this T obj) where T : Component { return GenericPool.IsInPool(obj); } public static bool IsInPool(this GameObject obj) { return GenericPool.IsInPool(obj); } public static int PoolIdleCount<T>(this T prefab) where T : Component { return GenericPool.PoolIdleCount(prefab); } public static int PoolIdleCount(this GameObject prefab) { return GenericPool.PoolIdleCount(prefab); } public static int PoolWorkCount<T>(this T prefab) where T : Component { return GenericPool.PoolWorkCount(prefab); } public static int PoolWorkCount(this GameObject prefab) { return GenericPool.PoolWorkCount(prefab); } public static List<T> GetPoolIdleItem<T>(this T prefab, List<T> list = null, bool appendList = true) where T : Component { return GenericPool.GetPoolIdleItem(prefab, list, appendList); } public static List<GameObject> GetPoolIdleItem(this GameObject prefab, List<GameObject> list = null, bool appendList = true) { return GenericPool.GetPoolIdleItem(prefab, list, appendList); } public static List<T> GetPoolWorkItem<T>(this T prefab, List<T> list = null, bool appendList = true) where T : Component { return GenericPool.GetPoolWorkItem(prefab, list, appendList); } public static List<GameObject> GetPoolWorkItem(this GameObject prefab, List<GameObject> list = null, bool appendList = true) { return GenericPool.GetPoolWorkItem(prefab, list, appendList); } }