1. 程式人生 > >通用物件池

通用物件池

最近做一款音樂遊戲,需要顯示較多的音符,需頻繁回收利用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);
        }

    }