通用物件池
阿新 • • 發佈:2018-12-18
最近做一款音樂遊戲,需要顯示較多的音符,需頻繁回收利用GameObject,簡易的物件池滿足不了需求,以前寫過幾個物件池, 使用起來有比較有侷限性,不是很方便,就考慮寫一個通用的物件池,可以適用於各種專案型別,而且呼叫要簡便。參考了一些資料,並利用This添加了靜態方法,方便呼叫,就此有了萬能物件池~(大佬們看見不要打我 ···)
使用前只需要建立一個池,載入物件到場景時呼叫建立方法,銷燬時呼叫回收方法即可~~
呼叫,對~ 就是這麼簡單,prefab可以是GameObject,也可以是任意元件、自定義的類,適用於各種情況。
void Test() { //建立物件池 prefab.CreatePool(); //生成池物件 prefab.Create(); //回收池物件 prefab.Reset(); }
物件池部分,程式碼比較簡單,不多說
public sealed class GenericPool : Singleton<GenericPool> { //預載入物件池啟動方式 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; void Awake() { 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 && !Instance.idlePoolDic.ContainsKey(prefab)) { List<GameObject> list = new List<GameObject>(); //建立父節點 Transform poolParent = new GameObject("Pool_" + prefab.name).transform; poolParent.gameObject.SetActive(false); poolParent.SetParent(Instance.transform); Instance.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); } } Instance.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 (Instance.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); Instance.workItemDic.Add(obj, prefab); return obj; } } obj = Instantiate(prefab); SetObjParame(obj, parent, position, rotation); Instance.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 (Instance.workItemDic.TryGetValue(obj, out prefab)) Reset(obj, prefab); else Destroy(obj); } static void Reset(GameObject obj, GameObject prefab) { Instance.idlePoolDic[prefab].Add(obj); Instance.workItemDic.Remove(obj); obj.transform.SetParent(Instance.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 Instance.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(Instance.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 (Instance.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(Instance.poolParentDic[prefab]); Instance.poolParentDic.Remove(prefab); } // ----- 獲取池狀態 ----- //是否已建立池 public static bool IsCreatPool<T>(T prefab) where T : Component { return IsCreatPool(prefab.gameObject); } public static bool IsCreatPool(GameObject prefab) { return Instance.idlePoolDic.ContainsKey(prefab); } //是否在物件池內 public static bool IsInPool<T>(T obj) where T : Component { return IsInPool(obj.gameObject); } public static bool IsInPool(GameObject obj) { return Instance.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 (Instance.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 Instance.workItemDic.Values) if (prefab == InstansePrefab) count++; return count; } //所有池內物件數量總和 public static int AllPoolIdleCount() { int count = 0; foreach (List<GameObject> list in Instance.idlePoolDic.Values) count += list.Count; return count; } //所有池外物件數量總和 public static int AllPoolWorkCount() { return Instance.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 (Instance.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 (Instance.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 Instance.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 Instance.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); } }