5评论

再谈对象池及扩展通用性

萧然 2018-10-20 1.5k浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594

最近做一款音乐游戏,需要显示较多的音符,需频繁回收利用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);
        }
    }