最新文章
泰课新年学课蛇来运转欢度春节活动
02-01 20:25
共庆2024圣诞、元旦泰课双蛋活动
12-16 10:21
泰课共庆75周年国庆活动!
10-05 21:24
暑假双月联动学习计划 7月15 - 8月21日
07-14 23:09
泰课在线劳动光荣,勤学快乐之五月勤学季活动
04-30 21:19
2024年青春绽放开学季活动
03-11 13:01
Unity中对象池的应用ObjectPool
为了更好地理解对象池,我们参考了这篇博客中的示例。对象池(ObjectPool)主要用于在游戏中新建和回收对象,避免频繁创建和销毁对象带来的性能开销。
1. 基本对象池类 ObjectPool
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);
}
// 使用ObjectInfo脚本保存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();
}
}
上述代码中,ObjectPool 类实现了对象池的基本功能。当从池中取出对象时,会将该对象从队列中移除;对象使用结束后,会通过 Recycle 方法将其回收至对象池。
2. 自定义对象池类 CubePool
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;
}
}
CubePool 类继承自 ObjectPool 类,并重写了 Get 方法,在获取对象时将对象的材质颜色随机设置。
3. 对象信息类 ObjectInfo
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);
}
}
ObjectInfo 类用于记录对象的信息,并在对象激活时启动协程进行倒计时,当倒计时结束后,将对象从对象池中移除。
4. 对象池管理类 ObjectPoolManager
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("ObjectPoolManager");
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].Recycle(go);
}
}
// 销毁所有对象池
public void Destroy()
{
m_PoolDic.Clear();
GameObject.Destroy(m_RootPoolTrans);
}
}
ObjectPoolManager 类用于管理多个对象池,提供了创建对象池、获取对象和移除对象等方法,并可以销毁所有对象池。
5. 回收方法的扩展
回收到对象池后可以进行属性重设,不同种类的对象池可以重写 Recycle 方法来重设不同的属性。示例代码如下:
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++;
}
}
6. 扩展学习
6.1 相关概念
- ObjectPoolContainer:对象容器
- ObjectPool:单一对象池
- PoolManager:对象池管理
6.2 扩展参考项目
UnityPool 是一个可以参考的扩展项目,有助于进一步学习 Unity 对象池的管理。