Unity3d中对象池(ObjectPool)的实现


1 2 | //回收接口。参数是待回收GameObject public static void recycle(GameObject recycleObj); |
1 2 | 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维护已分配的对象池实例
1 | private Dictionary<string, ObjectPool> poolDic = new Dictionary<string, ObjectPool>(); |
使用objectPoolList记录面板上的用户设置

ObjectPoolMgr初始化时会在Unity的层次(Hierarchy)面板中创建GameObject并添加自身脚本。开发者可以在Inspector面板中直接创建新的对象池,如下图。Pre Alloc Size是对象池创建时预申请的对象数量。Auto Increase Size是池中的对象被申请完后进行一定数量的自增。prefab对象池关联的预制类型

1 2 3 4 5 6 7 | 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,代码如下

1 2 3 4 5 6 7 8 9 10 | 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中的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | 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,进行个性化的申请和回收工作。
1 2 3 4 5 6 7 | 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等数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class PrefabInfo : 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脚本。如果不实现,这个对象池会使用通用的申请和回收方法。
调用申请和释放方法
1 2 3 4 5 6 | //申请GameObject obj1 = ObjectPoolMGR.alloc("Cube",5);GameObject obj2 = ObjectPoolMGR.alloc("Sphare");//回收ObjectPoolMGR.recycle(obj2); |



