47

再谈对象池及扩展通用性-腾讯游戏学院

 5 years ago
source link: http://gad.qq.com/article/detail/287817
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
最近做一款音乐游戏,需要显示较多的音符,需频繁回收利用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);
        }
    }



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK