用来理解对象池的简单示例使用了 https://blog.csdn.net/A13155283231/article/details/92098649 中的例子
ObjcetPool用来新建和回收游戏里的对象
public class ObjectPool
{
private Queue<GameObject> m_PoolQueue;
private string m_PoolName;
protected Transform m_Parent;
// 需要缓存的对象
private GameObject prefab;
// 最大容量
private int m_MaxCount;
protected const int m_DefaultMaxCount = 10;
public GameObject Prefab { get => prefab; set => prefab = value; }
public ObjectPool()
{
m_MaxCount = m_DefaultMaxCount;
m_PoolQueue = new Queue<GameObject>();
}
public virtual void Init(string poolName, Transform transform)
{
m_PoolName = poolName;
m_Parent = transform;
}
public virtual GameObject Get(Vector3 pos, float lifetime)
{
if (lifetime < 0)
{
return null;
}
GameObject returnObj;
if (m_PoolQueue.Count > 0)
{
returnObj = m_PoolQueue.Dequeue();
}
else
{
// 池中没有可分配对象了,新生成一个
returnObj = GameObject.Instantiate<GameObject>(prefab);
returnObj.transform.SetParent(m_Parent);
returnObj.SetActive(false);
}
// 使用PrefabInfo脚本保存returnObj的一些信息
ObjectInfo info = returnObj.GetComponent<ObjectInfo>();
if (info == null)
{
info = returnObj.AddComponent<ObjectInfo>();
}
info.PoolName = m_PoolName;
if (lifetime > 0)
{
info.Lifetime = lifetime;
}
returnObj.transform.position = pos;
returnObj.SetActive(true);
return returnObj;
}
// "销毁对象" 其实是回收对象
public virtual void Recycle(GameObject obj)
{
if (m_PoolQueue.Contains(obj))
{
return;
}
if (m_PoolQueue.Count > m_MaxCount)
{
// 对象池已满 直接销毁
GameObject.Destroy(obj);
}
else
{
// 放入对象池
m_PoolQueue.Enqueue(obj);
obj.SetActive(false);
}
}
public virtual void Destroy()
{
m_PoolQueue.Clear();
}
}
上面代码主要理解下从池中取出对象后,要从池中移除该对象
因为对象使用结束后会回到池中
CubePool.cs
public class CubePool : ObjectPool
{
public override GameObject Get(Vector3 pos, float lifetime)
{
GameObject obj;
obj = base.Get(pos, lifetime);
obj.GetComponent<Renderer>().material.color = Random.ColorHSV();
return obj;
}
}
ObjcetInfo.cs 用来记录对象信息 并且 定时回收对象
public class ObjectInfo : MonoBehaviour
{
public float Lifetime = 0;
public string PoolName;
private WaitForSeconds m_WaitTime;
private void Awake()
{
if (Lifetime > 0)
{
m_WaitTime = new WaitForSeconds(Lifetime);
}
}
private void OnEnable()
{
if (Lifetime > 0)
{
StartCoroutine(CountDown(Lifetime));
}
}
IEnumerator CountDown(float lifetime)
{
yield return m_WaitTime;
ObjectPoolManager.Instance.RemoveGameObject(PoolName, gameObject);
}
}
ObjcetPoolManager 用来管理多个对象池
public class ObjectPoolManager : Singleton<ObjectPoolManager>
{
private Dictionary<string, ObjectPool> m_PoolDic;
private Transform m_RootPoolTrans;
public ObjectPoolManager()
{
m_PoolDic = new Dictionary<string, ObjectPool>();
// 根对象池
GameObject go = new GameObject("ObjcetPoolManager");
m_RootPoolTrans = go.transform;
}
// 创建一个新的对象池
public T CreateObjectPool<T>(string poolName) where T : ObjectPool, new()
{
if (m_PoolDic.ContainsKey(poolName))
{
return m_PoolDic[poolName] as T;
}
GameObject obj = new GameObject(poolName);
obj.transform.SetParent(m_RootPoolTrans);
T pool = new T();
pool.Init(poolName, obj.transform);
m_PoolDic.Add(poolName, pool);
return pool;
}
public GameObject GetGameObject(string poolName, Vector3 position, float lifetTime)
{
if (m_PoolDic.ContainsKey(poolName))
{
return m_PoolDic[poolName].Get(position, lifetTime);
}
return null;
}
public void RemoveGameObject(string poolName, GameObject go)
{
if (m_PoolDic.ContainsKey(poolName))
{
m_PoolDic[poolName].Remove(go);
}
}
// 销毁所有对象池
public void Destroy()
{
m_PoolDic.Clear();javascript:void(0)
GameObject.Destroy(m_RootPoolTrans);
}
}
当然回收到对象池后可以进行属性重设的,不同种类的对象池可以重写这个方法重设不同的属性。比如
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++;
}
}
扩展学习Unity对象池的管理
ObjectPoolContainer 对象容器
ObjectPool 单一对象池
PoolManager 对象池管理