【Unity】动作游戏开发实战详细分析-10-对象池编写
基本思想
对象池,常用于缓存一定数量实例对象,并进行简单的隐藏操作,当需要它使用时显示即可。
它可以避免频繁的创建与销毁对象。相信大多数开发者对其都不会陌生。由于它涉及对象的创建逻辑,因此会与其他模块产生相当程度的耦合。
单个池可以管理对象的取出及取回状态不同类型的对象需要不同类型的池,但它们的共有逻辑是可以提炼的,我们可以给池赋予ID号,并在池管理器中注册与获取他们。
进入关卡后,首先会进行脚本配置,用以配置当前关卡中对不同池的缓存数量及不同策略,这样的脚本配置在每个关卡中都会出现。
存放在池中的对象在放回和取出时,需要得到对应的消息通知,较为简单的做法是借助Unity自身消息模块进行广播,或自行查找接口来分发。
代码实现
池管理器
首先我们需要一个池管理器,用于管理所有类型的对象池,它是一个单例
定义一些基本的方法,池管理器主要提供池的注册、注销、获取等操作。Prepare接口用于进入关卡后进行池大小的重设,ClearAll用于退出关卡时清空池对象的使用
public class PoolManager
{
static PoolManager mInstance;
public static PoolManager Instance { get { return mInstance ?? (mInstance = new PoolManager()); } }//单例
List<DefaultPool> mPoolList;//池List
public PoolManager()
{
mPoolList = new List<DefaultPool>();
}
public void RegistPool(DefaultPool pool)//注册池
{
mPoolList.Add(pool);
}
public void UnregistPool(DefaultPool pool)//反注册池
{
mPoolList.Remove(pool);
}
public DefaultPool GetPool(int id)//通过ID获取池
{
var result = default(DefaultPool);
for (int i = 0, iMax = mPoolList.Count; i < iMax; i++)
{
var item = mPoolList[i];
if (item.ID == id)
{
result = item;
break;
}
}
return result;
}
public void Prepare(int poolID, int poolSize)//重定义池缓存大小
{
GetPool(poolID).Prepare(poolSize);
}
public void ClearAll()//一般退出关卡时调用,清空所有池内对象
{
for (int i = 0, iMax = mPoolList.Count; i < iMax; i++)
mPoolList[i].Clear();//执行池对象的清空函数
}
}
池
定义基本字段
- 模版
- 父级
- 队列
- ID
- Size
基本方法:取出,放回,重置,清空
public class DefaultPool
{
const string MSG_POOL_TAKE = "OnPoolTake";//池取出消息
const string MSG_POOL_TAKE_BACK = "OnPoolTakeBack";//池放回消息
bool mSendPoolMessage;//是否发送消息
GameObject mTemplate;//模板
GameObject mParent;
protected Queue<GameObject> mMemberQueue;
public int ID { get; private set; }//ID
public int PoolSize { get; private set; }//池的的大小
public DefaultPool(int id, GameObject template, bool sendPoolMessage = true)
{
ID = id;
mTemplate = template;
mSendPoolMessage = sendPoolMessage;
mMemberQueue = new Queue<GameObject>();//初始化队列
mParent = new GameObject("(dynamic)Pool_" + id);
}
public virtual GameObject TakeItem()//取出物品
{
if (mMemberQueue.Count == 0) return null;//默认是非增量逻辑
var instanceGO = mMemberQueue.Dequeue();
instanceGO.SetActive(true);
if (mSendPoolMessage)
instanceGO.BroadcastMessage(MSG_POOL_TAKE, SendMessageOptions.DontRequireReceiver);
return instanceGO;
}
public virtual void TakeBackItem(GameObject go)//放回物品
{
if (mSendPoolMessage)
go.BroadcastMessage(MSG_POOL_TAKE_BACK, SendMessageOptions.DontRequireReceiver);
go.SetActive(false);
mMemberQueue.Enqueue(go);
}
public virtual void Prepare(int poolSize)//重置池的大小
{
PoolSize = poolSize;
Clear();//清空队列
for (int i = 0; i < poolSize; i++)
{
var instancedGO = UnityEngine.Object.Instantiate(mTemplate, Vector3.zero, Quaternion.identity, mParent.transform);
instancedGO.SetActive(false);
mMemberQueue.Enqueue(instancedGO);
}//重新添加
}
public virtual void Clear()//清空池中所有对象
{
while (mMemberQueue.Count > 0)
UnityEngine.Object.Destroy(mMemberQueue.Dequeue());
}
}