//回收接口。參數是待回收GameObject
public static void recycle(GameObject recycleObj);
public static GameObject alloc(string type,float lifetime = 0);
public static void recycle(GameObject recycleObj);
參數lifeTime是存活時間,以秒爲單位,定義如下
lifeTime > 0 lifeTime秒後自動回收對象。
lifeTime = 0 不自動回收對象,需遊戲主動調用recycle回收。
lifeTime < 0 創建Pool實例並實例化Pool中的對象,但不返回對象,返回值null。
當lifeTime>0時,分配出去的GameObject上掛的PrefabInfo腳本會執行倒計時協程,計時器爲0時調用recycle方法回收自己。它的適用對象如射擊遊戲中的子彈,申請時設定了lifeTime後不必關心回收的問題,當然遊戲可以計時器在到時前主動發起回收。
lifeTime < 0的目的預創建對象池,在遊戲場景Loading時可以用這個方法先把對象池創建起來,避免遊戲中創建對象池造成掉幀。
ObjectPoolMgr用成員poolDic維護已分配的對象池實例
private Dictionary<string,ObjectPool> poolDic = new Dictionary<string, ObjectPool>();
使用objectPoolList記錄面板上的用戶設置
ObjectPoolMgr初始化時會在Unity的層次(Hierarchy)面板中創建GameObject並添加自身腳本。開發者可以在Inspector面板中直接創建新的對象池,如下圖。Pre Alloc Size是對象池創建時預申請的對象數量。Auto Increase Size是池中的對象被申請完後進行一定數量的自增。prefab對象池關聯的預製類型
public static GameObject alloc(string type,float lifetime = 0){
//根據傳入type取出或創建對應類型對象池
ObjectPool subPool = Instance._getpool(type);
//從對象池中取一個對象返回
GameObject returnObj = subPool.alloc(lifetime);
return returnObj;
}
ObjectPoolMgr會根據傳入的類型type,調用_getpool(type)找到對應的Pool,再從其中取一個對象返回。
代碼中_getpool(string type)是ObjectPoolMgr中的私有方法。前面說過,ObjectPoolMgr有一個成員poolDic用來記錄已創建的對象池實例,_getpool方法先去poolDic中查找,找到直接返回。如果找不到說明還未創建,使用反射創建對象池,記錄入poolDic,代碼如下
protected Queue queue = new Queue();//用來保存池中對象
[SerializeField]
protected int _freeObjCount = 0;//池中待分配對象數量
public int preAllocCount;//初始化時預分配對象數量
public int autoIncreaseCount;//池中可增加對象數量
protected bool _binit = false;//是否初始化
[HideInInspector]
public GameObject prefab;//prefab引用
[HideInInspector]
public string objTypeString;//池中對象描述字符串
ObjectPool中的方法
public virtual GameObject alloc(float lifetime){
//如果沒有進行過初始化,先初始化創建池中的對象
if(!_binit){
_init();
_binit = true;
}
if(lifetime<0){
Debug.LogWarning("lifetime <= 0, return null");
return null;//lifetime<0時,創建對象池並返回null
}
GameObject returnObj;
if(_freeObjCount > 0){//池中有待分配對象
returnObj = queue.Dequeue();//分配
_freeObjCount--;
}else{//池中沒有對象了,實例化一個
returnObj = Instantiate(prefab , new Vector3(0,0,0), Quaternion.identity) as GameObject;
returnObj.SetActive(false);//防止掛在returnObj上的腳本自動開始執行
returnObj.transform.parent = this.transform;
}
//使用PrefabInfo腳本保存returnObj的一些信息
PrefabInfo info = returnObj.GetComponent<PrefabInfo>();
if(info == null){
info = returnObj.AddComponent<PrefabInfo>();
}
if(lifetime > 0){
info.lifetime = lifetime;
}
info.types = objTypeString;
returnObj.SetActive(true);
return returnObj;
}
public virtual void recycle(GameObject obj){
//待分配對象已經在對象池中
if(queue.Contains(obj)){
Debug.LogWarning("the obj " + obj.name + " be recycle twice!" );
return;
}
if( _freeObjCount > preAllocCount + autoIncreaseCount ){
Destroy(obj);//當前池中object數量已滿,直接銷燬
}else{
queue.Enqueue(obj);//入隊,並進行reset
obj.transform.parent = this.transform;
obj.SetActive(false);
_freeObjCount++;
}
}
這裏要注意的是,基類alloc和recycle方法要使用虛函數,子類override實現多態。
3>對象池子類CubePool
子類override父類的alloc和recycle,進行個性化的申請和回收工作。
public class CubePool : ObjectPool {
public override GameObject alloc(float lifetime){
GameObject cubeObject= base.alloc(lifetime);
//在這裏進行CubePool個性化的的初始化工作
return cubeObject;
}
}
當然也可以直接複用基類的alloc方法,甚至不寫CubePool類。當ObjectPoolMgr申請一個Cube但找不到CubePool類時,會使用通用方法進行分配和回收。
4>PrefabInfo
PrefabInfo是掛在prefab實例上,用來記錄prefab類型和lifetime等數據。
publicclassPrefabInfo : MonoBehaviour {
public string types;
[HideInInspector]
public float lifetime = 0;
void OnEnable(){
if(lifetime > 0){
StartCoroutine(countTime(lifetime));
}
}
IEnumerator countTime(float lifetime){
yield return new WaitForSeconds(lifetime);
ObjectPoolMGR.recycle(gameObject);
}
}
新增Pool方法
爲一個新Perfab創建對象池需要以下兩步,
1、在unity面板中把prefab掛上,並設置prefab的實例化數量和可增加數量
2、(可選)實現一個對應的Pool腳本。如果不實現,這個對象池會使用通用的申請和回收方法。
調用申請和釋放方法
//申請
GameObject obj1 = ObjectPoolMGR.alloc("Cube",5);
GameObject obj2 = ObjectPoolMGR.alloc("Sphare");
//回收
ObjectPoolMGR.recycle(obj2);