Unity 对象池技术应用

对象池就是用来避免频繁地创建和销毁对象而应用产生的。

对象池核心代码:

/*
 * author:maki
 * time:2019/12/8
 * 
 * Func与Action作用几乎一样。只是
 * Func<Result>有返回类型;
 * Action<T>只有参数类型,不能传返回类型。所以Action<T>的委托函数都是没有返回值的。
 * 
 * describe:对象池核心部分
 * */
using System;
using System.Collections.Generic;

namespace Assets.Scripts.Data.Utilities
{
    /// <summary>
    /// 对象池
    /// </summary>
     public class Pool<T>
    {
        /// <summary>
        /// 所有对象 总和列表
        /// </summary>
        protected readonly List<T> m_All;
        /// <summary>
        /// 可用的列表集合
        /// </summary>
        protected readonly List<T> m_Available;
        /// <summary>
        /// 初始创建对象时的回调函数
        /// </summary>
        protected Func<T> m_Factory;
        /// <summary>
        /// 重置对象时的回调函数
        /// </summary>
        protected readonly Action<T> m_Reset;

        /// <summary>
        /// 在给定数量的情况下,创建一个新的对象池
        /// </summary>
        /// <param name="factory"></param>
        /// <param name="reset"></param>
        /// <param name="InitCapacity"></param>
        public Pool(Func<T> factory,Action<T> reset, int InitCapacity)
        {
            if (factory == null) throw new ArgumentNullException("回调函数factory 为 null !");

            m_Available = new List<T>();
            m_All = new List<T>();
            m_Factory = factory;
            m_Reset = reset;
            if (InitCapacity > 0) InitItems(InitCapacity);
        }
        /// <summary>
        /// 创建一个空的对象池
        /// </summary>
        /// <param name="factory"></param>
        public Pool(Func<T> factory) : this(factory, null, 0)
        { }

        /// <summary>
        /// 创建一个新对象池,给定数量的物体
        /// </summary>
        /// <param name="factory"></param>
        /// <param name="initCapacity"></param>
        public Pool(Func<T> factory, int initCapacity) : this(factory, null, initCapacity)
        { }
        #region 对对象池中的对象进行增删查改
        /// <summary>
        /// 判断一个对象在池中是否存在
        /// </summary>
        /// <returns></returns>
        public virtual bool IsExit(T item)
        {
            return m_All.Contains(item);
        }

        /// <summary>
        /// 从池中获取一个对象
        /// </summary>
        /// <returns></returns>
        public virtual T Get()
        {
            return Get(m_Reset);
        }
        /// <summary>
        /// 得到一个重置的对象
        /// </summary>
        /// <param name="reset"></param>
        /// <returns></returns>
        public virtual T Get(Action<T> reset)
        {
            if (m_Available.Count == 0) InitItems(1);
            if (m_Available.Count == 0) throw new InvalidOperationException("创建对象池失败!!");

            int index = m_Available.Count - 1;
            T item = m_Available[index];
            m_Available.RemoveAt(index);
            if (reset != null) reset(item);
            return item;
        }

        /// <summary>
        /// 将一个对象重新返回(回收)到对象池中
        /// </summary>
        public virtual void Recycle(T item)
        {
            if (m_All.Contains(item)&&!m_Available.Contains(item))
            {
                RecycleToPool(item);
            }
            else
            {
                throw new InvalidOperationException("试图将一个对象回收到不包含它的池中:"+item+","+this);
            }
        }

        /// <summary>
        /// 将所有对象重新返回(回收)到对象池中
        /// </summary>
        public virtual void RecycleAll()
        {
            RecycleAll(null);
        }

        /// <summary>
        /// 将所有对象重新返回(回收)到对象池中
        /// i++是使用完 i 之后再使 i 加一
        ///++i是在使用 i 之前便使 i 加一
        ///如下,如果 i 的值为5
        ///b = i++; 语句之后 b 的值为5,i 的值为6,先对 b 赋值,然后 i 加一
        ///b = ++i; 语句之后 b 的值为6,i 的值为6,先对 i 加一,然后 b 赋值
        /// </summary>
        public virtual void RecycleAll(Action<T> preRecycle)
        {
            for (int i=0;i<m_All.Count;++i)
            {
                T item = m_All[i];
                if (!m_Available.Contains(item))
                {
                    if (preRecycle != null) preRecycle(item);
                }
                RecycleToPool(item);
            }
        }

        /// <summary>
        /// 将一个对象重新返回(回收)到对象池中
        /// </summary>
        /// <returns></returns>
        protected virtual void RecycleToPool(T item)
        {
            m_Available.Add(item);
        }

        /// <summary>
        /// 给定一个初始数量生成的对象池
        /// </summary>
        /// <param name="amount"></param>
        public void InitItems(int amount)
        {
            for (int i=0;i<amount;++i)
            {
                AddNewItem();
            }
        }
        /// <summary>
        ///向对象池中添加新的对象
        /// </summary>
        protected virtual T AddNewItem()
        {
            T item = m_Factory();
            m_All.Add(item);
            m_Available.Add(item);
            return item;
        }
        #endregion

        /// <summary>
        /// 默认值
        /// </summary>
        /// <returns></returns>
        protected static T DefaultFactory()
        {
            return default(T);
        }
    }
}

扩展部分:

1、应用于组件

/* ============================================================================== 
 * author:maki
 * time:2019/12/8
 * describe:对象池的继承类,用于Unity GameObject物体组件,据需要自动显示和隐藏
* ==============================================================================*/
using System;
using UnityEngine;
namespace Assets.Scripts.Data.Utilities
{
     public class PoolUnityComponent<T>:Pool<T> where T:Component
    {
        /// <summary>
        ///  创建一个对象池,给定一定数量的初始元素
        /// </summary>
        public PoolUnityComponent(Func<T> factory, Action<T> reset, int initCapacity) : base(factory, reset, initCapacity)
        { }
        /// <summary>
        ///  创建一个对象池,给定一定数量的初始元素
        /// </summary>
        public PoolUnityComponent(Func<T> factory) : base(factory)
        { }
        /// <summary>
        ///  创建一个对象池,给定一定数量的初始元素
        /// </summary>
        public PoolUnityComponent(Func<T> factory, int initCapacity) : base(factory, initCapacity)
        { }

        /// <summary>
        /// 使用(激活/显示)对象池中的物体对象
        /// </summary>
        public override T Get(Action<T> reset)
        {
            T item = base.Get(reset);
            item.gameObject.SetActive(true);

            return item;
        }

        /// <summary>
        /// 自动隐藏回收物体对象到对象池中
        /// </summary>
        /// <param name="item"></param>
        protected override void RecycleToPool(T item)
        {
            item.gameObject.SetActive(false);

            base.RecycleToPool(item);
        }

        /// <summary>
        ///  创建一个新的对象物体到对象池中,并隐藏它
        /// </summary>
        /// <returns></returns>
        protected override T AddNewItem()
        {
            T item = base.AddNewItem();
            item.gameObject.SetActive(false);

            return item;
        }
    }
}
/* ============================================================================== 
 * author:maki
 * time:2019/12/8
 * describe:在对象池中自动实例化一个给定的unity组件对应的预制对象
* ==============================================================================*/
using System;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Assets.Scripts.Data.Utilities
{
     public class PoolUnityComponentAuto<T>:PoolUnityComponent<T> where T:Component
    {
        /// <summary>
        /// 物体对象的预制体(根)
        /// </summary>
        protected readonly T m_Prefab;

        /// <summary>
        /// 物体对象初始化的回调函数
        /// </summary>
        protected readonly Action<T> m_InitObj;

        /// <summary>
        /// 根据预制体对象创建一个新的对象池
        /// </summary>
        public PoolUnityComponentAuto(T prefab) : this(prefab, null, null, 0)
        { }

        /// <summary>
        /// 根据预制体对象创建一个新的对象池
        /// </summary>
        public PoolUnityComponentAuto(T prefab, Action<T> initObj, Action<T> reset) : this(prefab, initObj, reset, 0)
        { }

        /// <summary>
        /// 根据预制体对象创建一个新的对象池
        /// </summary>
        public PoolUnityComponentAuto(T prefab, int initCapacity) : this(prefab, null, null, initCapacity)
        { }

        /// <summary>
        /// 根据预制体对象创建一个新的对象池
        /// </summary>
        public PoolUnityComponentAuto(T prefab, Action<T> initObj, Action<T> reset, int initCapacity) : base(DefaultFactory, reset, 0)
        {
            //设置初始容量,根据预制体生成所需的物体对象
            m_InitObj = initObj;
            m_Prefab = prefab;
            m_Factory = PrefabFactory;

            if (initCapacity > 0) InitItems(initCapacity);
        }

        /// <summary>
        /// 创建预制体的克隆体
        /// </summary>
        /// <returns></returns>
        private T PrefabFactory()
        {
            T item = Object.Instantiate(m_Prefab);
            if (m_InitObj != null) m_InitObj(item);
            return item;
        }
    }
}

2、应用于Gameobject预制体对象

/* ============================================================================== 
 * author:maki
 * time:2019/12/8
 * describe:对象池的继承类,用于Unity GameObject物体据需要自动显示和隐藏
* ==============================================================================*/
using System;
using UnityEngine;

namespace Assets.Scripts.Data.Utilities
{
    public class PoolGameObject:Pool<GameObject>
    {
        /// <summary>
        /// 创建一个对象池,给定一定数量的初始元素
        /// </summary>
        public PoolGameObject(Func<GameObject> factory,Action<GameObject> reset,int initCapacity) : base(factory,reset, initCapacity)
        { }

        /// <summary>
        /// 创建一个空白的对象池
        /// </summary>
        public PoolGameObject(Func<GameObject> factory) : base(factory)
        { }

        /// <summary>
        ///创建一个对象池,给定一定数量的初始元素
        /// </summary>
        public PoolGameObject(Func<GameObject> factory, int initCapacity) : base(factory, initCapacity)
        { }

        /// <summary>
        /// 使用(激活/显示)对象池中的物体对象
        /// </summary>
        public override GameObject Get(Action<GameObject> reset)
        {
            GameObject item = base.Get(reset);
            item.SetActive(true);

            return item;
        }

        /// <summary>
        /// 自动隐藏回收物体对象到对象池中
        /// </summary>
        /// <param name="item"></param>
        protected override void RecycleToPool(GameObject item)
        {
            item.SetActive(false);
            base.RecycleToPool(item);
        }

        /// <summary>
        /// 创建一个新的对象物体到对象池中,并隐藏它
        /// </summary>
        /// <returns></returns>
        protected override GameObject AddNewItem()
        {
            GameObject item= base.AddNewItem();
            item.SetActive(false);
            return item;
        }
    }
}
/* ============================================================================== 
 * author:maki
 * time:2019/12/8
 * describe:在对象池中自动实例化一个给定的unity游戏预制对象
* ==============================================================================*/
using System;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Assets.Scripts.Data.Utilities
{
     public class PoolGameObjectAuto:PoolGameObject
    {

        /// <summary>
        /// 物体对象的预制体(根)
        /// </summary>
        protected readonly GameObject m_Prefab;

        /// <summary>
        /// 物体对象初始化的回调函数
        /// </summary>
        protected readonly Action<GameObject> m_InitObj;

        /// <summary>
        /// 根据预制体对象创建一个新的对象池
        /// </summary>
        public PoolGameObjectAuto(GameObject prefab) : this(prefab, null, null, 0)
        { }

        /// <summary>
        /// 根据预制体对象创建一个新的对象池
        /// </summary>
        public PoolGameObjectAuto(GameObject prefab, Action<GameObject> initObj, Action<GameObject> reset) : this(prefab, initObj, reset, 0)
        { }

        /// <summary>
        /// 根据预制体对象创建一个新的对象池
        /// </summary>
        public PoolGameObjectAuto(GameObject prefab, int initCapacity) : this(prefab, null,null, initCapacity)
        { }

        /// <summary>
        /// 根据预制体对象创建一个新的对象池
        /// </summary>
        public PoolGameObjectAuto(GameObject prefab,Action<GameObject> initObj,Action<GameObject> reset,int initCapacity) : base(DefaultFactory,reset,0)
        {
            //设置初始容量,根据预制体生成所需的物体对象
            m_InitObj = initObj;
            m_Prefab = prefab;
            m_Factory = PrefabFactory;

            if (initCapacity > 0) InitItems(initCapacity);
        }

        /// <summary>
        /// 创建预制体的克隆体
        /// </summary>
        /// <returns></returns>
        private GameObject PrefabFactory()
        {
            GameObject item = Object.Instantiate(m_Prefab);
            if (m_InitObj != null) m_InitObj(item);
            return item;
        }
    }
}

创建对象池管理类,挂载到生成对象的父项,利用单例:https://blog.csdn.net/qq_40120946/article/details/103407720

直接调用

 

/* ============================================================================== 
 * author:maki
 * time:2019/12/8
 * describe:对象池的管理类,管理对象池的获取和回收
* ==============================================================================*/
using Core.Utilities;
using System.Collections.Generic;
using UnityEngine;

namespace Assets.Scripts.Data.Utilities
{
     public class PoolManager: Singleton<PoolManager>
    {
        /// <summary>
        /// 用于初始化相应池的池的列表
        /// </summary>
        public List<PoolItem> poolItems;
        /// <summary>
        /// 对象池存储的字典
        /// </summary>
        protected Dictionary<PoolItem, PoolUnityComponentAuto<PoolItem>> m_PoolDic;
        /// <summary>
        /// 初始化
        /// </summary>
        protected void Start()
        {
            m_PoolDic = new Dictionary<PoolItem, PoolUnityComponentAuto<PoolItem>>();

            for (int i =0;i<poolItems.Count;i++)
            {
                var item = poolItems[i];
                if (item == null) continue;
                item.gameObject.SetActive(true);
                m_PoolDic.Add(item,new PoolUnityComponentAuto<PoolItem>(item,InitComponent,null,item.initPoolCapacity));
            }
        }

        /// <summary>
        /// 对象池对象回调
        /// </summary>
        /// <param name="item"></param>
        private void InitComponent(Component item)
        {
            item.transform.SetParent(transform,false);
        }

        /// <summary>
        /// 从对象池中获取对象组件
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public PoolItem GetPoolItem(PoolItem item)
        {
            if (!m_PoolDic.ContainsKey(item))
            {
                m_PoolDic.Add(item,new PoolUnityComponentAuto<PoolItem>(item,InitComponent,null,item.initPoolCapacity));
            }
            PoolUnityComponentAuto<PoolItem> pool = m_PoolDic[item];

            PoolItem itemInstance = pool.Get();

            itemInstance.pool = pool;
            return itemInstance;
        }

        /// <summary>
        /// 从组件池中回收组件对象
        /// </summary>
        public void RecyclePoolItem(PoolItem item)
        {
            item.pool.Recycle(item);
        }
    }
}

创建单个物体挂载代码,方便管理类生成添加。重复利用和销毁

/* ============================================================================== 
 * author:maki
 * time:2019/12/8
 * describe:对象池的子项,需要挂载对象池中物体对象身上
* ==============================================================================*/
using UnityEngine;

namespace Assets.Scripts.Data.Utilities
{
    public class PoolItem : MonoBehaviour
    {
        /// <summary>
        /// 初始化池的数量
        /// </summary>
        public int initPoolCapacity = 10;
        /// <summary>
        /// 本对象所属池
        /// </summary>
        public Pool<PoolItem> pool;

        /// <summary>
        /// 如果对象池中存在对象则返回一个对象组件,如果没有则实例化一个并返回组件
        /// </summary>
        public static T TryGetPoolable<T>(GameObject obj) where T : Component
        {
            var item = obj.GetComponent<PoolItem>();

            if (item!=null&&PoolManager.Exists)
            {
                return PoolManager.Instance.GetPoolItem(item).GetComponent<T>();
            }
            else
            {
                return Instantiate(obj).GetComponent<T>();
            }
        }
        /// <summary>
        /// 如果对象池中存在对象则返回一个对象,如果没有则实例化一个
        /// </summary>
        public static GameObject TryGetPoolable(GameObject obj)
        {
            var item = obj.GetComponent<PoolItem>();

            if (item != null && PoolManager.Exists)
            {
                return PoolManager.Instance.GetPoolItem(item).gameObject;
            }
            else
            {
                return Instantiate(obj);
            }
        }

        /// <summary>
        ///回收到对象池中
        /// </summary>
        public static void TryPool(GameObject obj)
        {
            var item = obj.GetComponent<PoolItem>();
            if (item != null&& item.pool!=null&&PoolManager.Exists)
            {
                item.RecyclePool();
            }
            else
            {
                Destroy(obj);
            }
        }
        /// <summary>
        /// 回收到对象池中
        /// </summary>
        protected virtual void RecyclePool()
        {
            transform.SetParent(PoolManager.Instance.transform,false);
            pool.Recycle(this);
        }

    }
}

测试部分,

生成:

public class PoolTest : MonoBehaviour
{
    public GameObject cube;

    public GameObject sphere;

    public void OnClick()
    {
        var _cube = PoolItem.TryGetPoolable(cube);
        _cube.SetActive(true);
        _cube.transform.position = cube.transform.position;
        _cube.transform.parent = PoolManager.Instance.transform;


        var _sphere = PoolItem.TryGetPoolable(sphere);
        _sphere.SetActive(true);
        _sphere.transform.position = sphere.transform.position;
        _sphere.transform.parent = PoolManager.Instance.transform;
    }
}

回收:

private void OnCollisionEnter(Collision collision)
    {
        PoolItem.TryPool(gameObject);
    }

测试效果:

项目工程链接:https://download.csdn.net/download/qq_40120946/12029035

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值