关于unity的对象池系统 网上也是有很多了 这里我记录一下 我这边的实现和用法 这里的对象池会根据类别进行区分,不需要了的对象会设置为不激活并且挂载在表示这个类别的游戏物体下面作为子物体, 重复调用某个类别的对象会先去对象池查看是否已经有了此类别的对象存储,有的话就解除挂载子物体关系取出来再次使用,没有就会新创建一个,支持预制体形式创建。先来对象池总管理类代码,总管理类脚本不需要挂载在游戏物体上。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PoolMgr { /// <summary> /// 存放所有的对象池 /// </summary> Dictionary<string, BasePool> poolDic; Dictionary<string, GameObject> storeHangGoDic; private static PoolMgr instance; public static PoolMgr Instance { get { if (instance == null) { instance = new PoolMgr(); } return instance; } set { instance = value; } } GameObject poolGoTotal; public PoolMgr() { poolDic = new Dictionary<string, BasePool>(); storeHangGoDic = new Dictionary<string, GameObject>(); //生成一个新的GameObject存放所有的对象池对象 poolGoTotal = new GameObject("GameObjectPoolManager"); } /// <summary> /// 返回对象池 /// </summary> /// <typeparam name="T">对象池类型</typeparam> /// <param name="poolName">对象池名称,唯一id</param> /// <returns>对象池对象</returns> T GetGameObjectPool<T>(string poolName) where T : BasePool, new() { //Debug.LogError(poolName); if (poolDic.ContainsKey(poolName)) { return (T)poolDic[poolName]; } T pool = new T(); pool.Init(poolName); poolDic.Add(poolName, pool); GameObject subGoPool = new GameObject(poolName); subGoPool.transform.parent = poolGoTotal.transform; storeHangGoDic.Add(poolName, subGoPool); return pool; } /// <summary> /// 从某类型对象池中取出新的对象 /// 公共取接口 /// </summary> /// <param name="poolName">对象池名称</param> /// <param name="parentTrn">对象父物体</param> /// <returns>新对象</returns> public GameObject GetGameObject<T>(string poolName, Transform parentTrn = null, GameObject prefGo = null) where T : BasePool, new() { return GetGameObjectPool<T>(poolName).GetObj(parentTrn, prefGo); } /// <summary> /// 将对象存入某类型的对象池中 /// 公共存接口 /// </summary> /// <param name="poolName">对象池名称</param> /// <param name="go">对象</param> public void PushGameObject(object[] parameters) { string poolName = parameters[0] as string; GameObject go = (GameObject)parameters[1]; if (poolDic.ContainsKey(poolName)) { bool pushSucceed = poolDic[poolName].PushObj(go); //Debug.LogError(" PoolMgr PushGameObject pushSucceed " + pushSucceed); if (pushSucceed) { go.transform.parent = storeHangGoDic[poolName].transform; } } } /// <summary> /// 销毁所有对象池操作 /// </summary> public void Destroy() { poolDic.Clear(); } }然后是某个类别的对象池的基类代码。
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; public class BasePool { /// <summary> /// 队列,存放对象池中没有用到的对象,即 可分配对象 /// </summary> protected Queue objQueue; /// <summary> /// 对象池中存放最大数量 /// </summary> protected int maxCount; /// <summary> /// 每个对象池的名称,当唯一id /// </summary> protected string poolName; /// <summary> /// 默认最大容量 /// </summary> protected const int defaultMaxCount = 20; protected Action<GameObject> instantiateAct; public BasePool() { maxCount = defaultMaxCount; objQueue = new Queue(); } public virtual void Init(string poolName) { this.poolName = poolName; SetAction(); } /// <summary> /// 继承自BasePool的类根据需要重写此方法 进行定义对象池子物体的初始化操作 /// 通过对象池生成某个游戏物体的时候会对这个生成的物体进行一些操作 /// </summary> public virtual void SetAction() { instantiateAct += (GameObject go)=> { go.AddComponent<PoolDestroyBehaviour>().Init(poolName, PoolMgr.Instance.PushGameObject); }; } public int MaxCount { set { maxCount = value; } } /// <summary> /// 生成一个对象池对象 /// </summary> /// <param name="parentTrn">生成的对象的父物体</param> /// <returns></returns> public virtual GameObject Instantiate(Transform parentTrn, GameObject prefGo = null) { GameObject returnObj; if (prefGo == null) { returnObj = new GameObject(); } else { returnObj = GameObject.Instantiate(prefGo); } returnObj.transform.SetParent(parentTrn); returnObj.SetActive(false); instantiateAct(returnObj); return returnObj; } /// <summary> /// 生成一个对象 /// </summary> /// <returns>生成的对象</returns> public virtual GameObject GetObj(Transform parentTrn = null, GameObject prefGo = null) { GameObject returnObj; Debug.LogError(" BasePool GetObj "); if (objQueue.Count > 0) { //池中有待分配对象 returnObj = (GameObject)objQueue.Dequeue(); } else { //池中没有可分配对象了,新生成一个 returnObj = Instantiate(parentTrn, prefGo); } returnObj.transform.parent = null; returnObj.SetActive(true); return returnObj; } /// <summary> /// “删除对象”放入对象池 /// </summary> /// <param name="obj">对象</param> public virtual bool PushObj(GameObject obj) { //Debug.LogError("BasePool PushObj "); //待分配对象已经在对象池中 if (objQueue.Contains(obj)) { return false; } if (objQueue.Count > maxCount) { //当前池中object数量已满 GameObject.Destroy(obj); return false; } //放入对象池,入队 objQueue.Enqueue(obj); obj.SetActive(false); return true; } /// <summary> /// 销毁该对象池 /// </summary> public virtual void Destroy() { objQueue.Clear(); } }然后继承了BasePool 类的有需要可以重写SetAction方法,该方法定义了新创建一个该类别的对象需要的初始化操作,在SetAction里面对一个新创建的空物体或者实例化出来的预制体再执行一些需要的操作
/// <summary> /// 匀速直线运动投掷物 /// </summary> public class BaseUniformSpdStraightLineProjectilePool : BasePool { public override void SetAction() { instantiateAct = (GameObject go) => { Util.AddCompOnce<Rigidbody2D>(go); }; base.SetAction(); } }然后是对象上面需要挂载一个执行销毁的脚本。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using System; using UnityEngine.Networking; public class PoolDestroyBehaviour : Monobehaviour { protected DestroyCBDelegate destroyCallBack; public delegate void DestroyCBDelegate(params object[] bc); protected string poolName; public virtual void Init(string poolName, DestroyCBDelegate cb) { //Debug.LogError("PoolDestroyBehaviour SetDesrtoyCB " + cb); this.poolName = poolName; destroyCallBack = cb; } /// <summary> /// 回收时候的回调函数 /// </summary> public virtual void PoolDestroy() { //Debug.LogError("PoolDestroyBehaviour Destroy " + destroyCallBack); destroyCallBack?.Invoke(poolName, gameObject); } }下面是初始化一个对象池对象的语句
GameObject projectileInstance = PoolMgr.Instance.GetGameObject<EnemyParaProj1Pool>(parabolaProjectilePoolTypeStr, null, projectilePref);这里面泛型是继承自basePool的一个类,第一个参数是这个类别对象池的名字,对象池系统将会创建一个同名的游戏空物体用于挂载这个类别的回收后的对象,可以直接在inspector里面看到
根据各种实际情况,在需要销毁对象的时候只需要调用PoolDestroyBehaviour 的PoolDestroy函数即可,可以使用sendMessage调用
