(说明部分后面会写,这里先展示实现)
代码实现(Unity)
三个类
- Pool (管理 PoolObject,针对单个预制体)
- PoolObject(池对象)
- PoolManager(管理 Pool)
PoolObject
namespace GameObjectPool
{
/// <summary>
/// 池中对象
/// </summary>
public class PoolObject : MonoBehaviour
{
//名字
public string poolName;
//是否在池中
public bool isPool;
}
}
Pool
using System.Collections.Generic;
using MyMath;
using UnityEngine;
namespace GameObjectPool
{
public class Pool
{
//池中可用对象
private Queue<PoolObject> _availableObjects = new Queue<PoolObject>();
//池的名字
private string _poolName;
//对象的预制体
private GameObject _prefab;
//池的大小(不是池中有多少对象,是池的大小)
private int _poolSize;
public Pool(string poolName, GameObject prefab, int poolSize)
{
_poolName = poolName;
_prefab = prefab;
_poolSize = poolSize;
//填充对应数目的对象
for (int i = 0; i < poolSize; i++)
AddObjectToPool(CreatePoolObject());
}
private void AddObjectToPool(PoolObject po)
{
//进入队列
_availableObjects.Enqueue(po);
po.gameObject.SetActive(false);
po.isPool = true;
}
private PoolObject CreatePoolObject()
{
GameObject go = Object.Instantiate(_prefab);
if (!go.TryGetComponent(out PoolObject po))
po = go.AddComponent<PoolObject>();
po.poolName = _poolName;
return po;
}
/// <summary>
/// 获得一个池对象(队列有则返回,没有则创建并返回)
/// </summary>
/// <returns></returns>
public PoolObject GetAvailableObject(Vec3 pos, Quat rot)
{
PoolObject po = null;
if (_availableObjects.Count > 0)
po = _availableObjects.Dequeue();
else
{
po = CreatePoolObject();
_poolSize++;
}
GameObject go = null;
if (po != null)
{
po.isPool = false;
go = po.gameObject;
go.SetActive(true);
go.transform.SetPositionAndRotation(pos.ToVector3, rot.ToQuaternion);
}
return po;
}
/// <summary>
/// 回收池对象
/// </summary>
/// <param name="po"></param>
public void RecyclePoolObject(PoolObject po)
{
if (_poolName.Equals(po.poolName))
{
if (po.isPool)
Debug.LogWarning(po.gameObject.name + " is already in pool.");
else
AddObjectToPool(po);
}
else
Debug.LogError($"Trying to add object to incorrect pool {
po.poolName} {
_poolName}");
}
}
}
PoolManager
using System;
using System.Collections.Generic;
using MyMath;
using Other;
using UnityEngine;
namespace GameObjectPool
{
[System.Serializable]
public class PoolInfo
{
public string name;
public GameObject prefab;
public int count;
}
/// <summary>
/// 池管理类(单例)
/// </summary>
public class PoolManager : Singleton<PoolManager>
{
[SerializeField] private PoolInfo[] _poolInfos;
private Dictionary<string, Pool> _poolMap = new Dictionary<string, Pool>();
private void Start()
{
CheckPoolName();
CreatePool();
}
/// <summary>
/// 检测池的名称是否重复
/// </summary>
private void CheckPoolName()
{
for (int i = 0; i < _poolInfos.Length; i++)
for (int j = i + 1; j < _poolInfos.Length; j++)
if (_poolInfos[i].name.Equals(_poolInfos[j].name))
Debug.LogError($"Pool {
i} & {
j} have the same name. Assign different names.");
}
private void CreatePool()
{
foreach (var info in _poolInfos)
{
_poolMap.Add(info.name, new Pool(info.name, info.prefab, info.count));
}
}
public PoolObject GetPoolObject(string poolName, Vec3 pos, Quat rot)
{
PoolObject po = null;
if (_poolMap.ContainsKey(poolName))
po = _poolMap[poolName].GetAvailableObject(pos, rot);
else
Debug.LogError("Invalid pool name specified : " + poolName);
return po;
}
public void RecyclePoolObject(PoolObject po)
{
if (po == null)
Debug.LogWarning("Specified object is not a pooled instance: " + po.poolName);
else
{
if (_poolMap.ContainsKey(po.poolName))
_poolMap[po.poolName].RecyclePoolObject(po);
else
Debug.LogError("No pool available with name : " + po.poolName);
}
}
}
}