一、对象池思想
1.使用对象池的好处
很多情况下,我们需要创建大量对象,例如发射子弹,或者大量的AI小兵,不断重新的生成和销毁对象会对性能造成巨大的消耗,所以我们考虑使用对象池技术来管理需大量生成的对象。
2.对象池的组成
对象池的核心包括对象池控制器类(ObjectCtrl)、对象池类(SubPool)以及对象池中具体存放的物品类(obj),当有多个对象时通过SubPool中的list集合进行管理,而当有多个对象池,则通过ObjectCtrl中的Dictionary集合进行管理
ObjectCtrl
ObjectCtrl 好比仓库经理,而SubPool是具体的物品管理员。当你需要使用某件物品时去找仓库经理,仓库经理便通知物品管理员拿给你;当你需要借的物品种类仓库还没有,他则会招聘一个新的物品管理员(RegisterSubPool())。当然,物品的借出和归还你都是和仓库经理进行沟通的,不会直接接触下面的每个物品管理员。
SubPool
SubPool负责具体的物品管理。当物品数量充足时,SubPool只要负责将已有的物品往外拿;当数量不够时,SubPool便会去购置更多物品,即增加对象池总的对象数量。SubPool中存放物品的最大数量等于你同时需要的最大数量,例如场景中同时最多只能产生100个小兵,那么负责管理小兵的对象池中最多就要放100个对象就OK了。
obj类
具体的物品,拿出时需要将各种参数调好以保证正常使用,而归还时需要还原出厂设置便于下次借出。
二、实现代码
1.ReuseObject接口
创建一个接口,用于限定对象池中所保存的对象的基本行为:
public interface IReusable {
void Spawn();
void UnSpawn();
}
对象池中的每个对象需要继承这个接口并实现接口中的方法,Spawn()方法是卵生物体之后所执行的操作,例如小怪属性的初始化;UnSpawn()方法回收物体之后所执行的操作,例如停止导航。
2.SubPool对象池类
对象池中的对象用List进行管理,便于动态扩展。对象池中保存的对象均为隐藏状态,当从对象池中获取对象后,该对象的状态变为显示,同时对象执行1中接口的Spawn()方法完成初始化。使用完毕后归还到对象池,状态变为隐藏,同时执行1中接口的UnSpaw())方法归0所有状态。
public class SubPool {
//对象集合
List<GameObject> m_pool = new List<GameObject>();
//预设体引用
GameObject m_prefab;
public string Name
{
get {
return m_prefab.name;
}
}
public SubPool(GameObject prefab)
{
this.m_prefab = prefab;
}
public GameObject Spawn()
{
GameObject obj = null;
foreach (GameObject x in m_pool)
{
if (!x.activeSelf) { //如果物体是隐藏的
obj = x;
break;
}
}
if (obj == null) {
obj = GameObject.Instantiate(m_prefab);
m_pool.Add(obj);
}
obj.SetActive(true); //物体显示出来
//执行物体的卵生方法
IReusable reusable = obj.GetComponent<IReusable>();
if (reusable != null) {
reusable.Spawn();
}
return obj;
}
//回收物体
public void UnSpawn(GameObject go)
{
if (m_pool.Contains(go))
{
//执行物体的放回操作
IReusable reusable = go.GetComponent<IReusable>();
if (reusable != null)
{
reusable.UnSpawn();
}
//隐藏
go.SetActive(false);
}
}
//回收所有物体
public void UnSpawnAll()
{
foreach(GameObject go in m_pool)
{
if (go.activeSelf)
{
//执行物体的放回操作
IReusable reusable = go.GetComponent<IReusable>();
if (reusable != null)
{
reusable.UnSpawn();
}
//隐藏
go.SetActive(false);
}
}
}
public bool Contains(GameObject go)
{
return m_pool.Contains(go);
}
}
3.ObjectCtrl 对象池控制器
如果有很多不同的物体则需要建立多个SubPool对象,当同时存在多个不同的对象池时,需要用控制器进行管理。用Dictionary集合存放所有的对象池,并用对象的名字进行索引。在使用时,即通过对象池控制器生成和释放具体的对象。
public class ObjectPoolCtrl : MonoSingleton<ObjectPoolCtrl> {
private Dictionary<string, SubPool> m_pools = new Dictionary<string, SubPool>();
//从对象池取物体
public GameObject Spawn(string name)
{
//查找对象池
SubPool pool;
if (!m_pools.ContainsKey(name))
{
RegisterSubPool(name);
}
//取出对应的对象池,并调用Spawn方法
pool = m_pools[name];
return pool.Spawn();
}
//注册一个对象池
private void RegisterSubPool(string name)
{
GameObject prefab = Resources.Load<GameObject>(name);
SubPool pool = new SubPool(prefab);
m_pools.Add(pool.Name, pool);
}
public void UnSpawn(GameObject go)
{
foreach (SubPool pool in m_pools.Values)
{
if (pool.Contains(go)) {
pool.UnSpawn(go);
break;
}
}
}
}