这项优化方法又是从别的领域借鉴来的, 最开始了解的一个东西是线程池,内存池。
其实不论是线程池还是内存池,都在游戏引擎中非常常见,首先我们先介绍一下他们的应用场景,因为在游戏引擎里我们常常遇到这样一个问题,那就是内存(线程)的申请和释放非常频繁,虽然这块线程或者说内存的申请的数目或者大小不多,但是不论是内存的申请、释放或者是线程的申请、释放,都会导致要让操作系统在用户态和核心态之间还会切换,这是一项很耗时的操作。
所以前辈们就想到一种以空间换时间的方式,就是可以提前预申请一大块内存,一大堆线程,然后先不用,不唤醒,用一个管理系统去存储他们,于是在用户申请内存或者线程的时候,就不是向操作系统提出申请,而是向这个我们自己的管理系统提出申请。往往这就是一个移动指针的时间——虽然这种方式实际用掉了很多待机的空间。
在我们做AI的时候,同样面临着这个问题,有一些AI,是死亡和生成非常频繁,比如Boss召唤的自爆兵,偏偏这些东西数量还可能很大。而Instantiate和Destroy,偏偏又是两个很耗时的操作,所以我们同样使用了AI池的技术。
public class AIPoorComponent:UComponent
{
public GameObject mAI_Template;
public AIEntity[] mAIPoor = new AIEntity[3000];
public int mMaxCount = 3000;
private int mTempCount = 0;
public override void Init ()
{
for (int i = 0; i < mMaxCount; i++)
{
mAIPoor [i].mAI = mAI_Template;
mAIPoor [i].Init ();
mAIPoor [i].GetComponent<BaseAIComponent> ().mPoorID = i;
}
}
public override void Release ()
{
for (int i = 0; i < mMaxCount; i++)
{
mAIPoor [i].Release ();
}
}
public void DestroyEntity(int id)
{
mUEntity.mWorld.deleteEntity (mAIPoor[id]);
mAIPoor [id].GetComponent<BaseAIComponent> ().mAIRT.SetActive (false);
AIEntity temp = mAIPoor [id];
mAIPoor [id] = mAIPoor[mTempCount-1];
mAIPoor [mTempCount - 1] = temp;
mAIPoor [id].GetComponent<BaseAIComponent> ().mPoorID = id;
mAIPoor [mTempCount - 1].GetComponent<BaseAIComponent> ().mPoorID = mTempCount - 1;
mTempCount--;
}
public AIEntity InstantiateEntity()
{
mAIPoor [mTempCount].mAllBitBunch.SetCount ((int)mUEntity.mWorld.mComponentCount);
mUEntity.mWorld.registerEntity (mAIPoor[mTempCount]);
mAIPoor [mTempCount].GetComponent<BaseAIComponent> ().mAIRT.SetActive (true);
mTempCount++;
return mAIPoor [mTempCount - 1];
}
}
首先这个管理器会有一个模板,也就是这些AI的Prefab,然后在游戏一开始,我们就生成了一大堆这个玩意,然后都不激活他。
然后我们可以看到,Instantiate和Destroy在这里,仅仅只是移动一下数组指针,和激活一下GameObject的操作。