对象池就是用来避免频繁地创建和销毁对象而应用产生的。
对象池核心代码:
/*
* 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