这项优化方法又是从别的领域借鉴来的, 最开始了解的一个东西是线程池,内存池。
其实不论是线程池还是内存池,都在游戏引擎中非常常见,首先我们先介绍一下他们的应用场景,因为在游戏引擎里我们常常遇到这样一个问题,那就是内存(线程)的申请和释放非常频繁,虽然这块线程或者说内存的申请的数目或者大小不多,但是不论是内存的申请、释放或者是线程的申请、释放,都会导致要让操作系统在用户态和核心态之间还会切换,这是一项很耗时的操作。
所以前辈们就想到一种以空间换时间的方式,就是可以提前预申请一大块内存,一大堆线程,然后先不用,不唤醒,用一个管理系统去存储他们,于是在用户申请内存或者线程的时候,就不是向操作系统提出申请,而是向这个我们自己的管理系统提出申请。往往这就是一个移动指针的时间——虽然这种方式实际用掉了很多待机的空间。
在我们做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的操作。