在游戏开发中,频繁创建和销毁对象会带来性能开销,尤其是子弹、特效、怪物等需要反复生成的对象。Unity在 Instantiate 和 Destroy 时会触发内存分配与垃圾回收 (GC),如果数量较多,可能导致帧率波动和卡顿。
对象池 (Object Pool) 的核心思想是:一次性创建对象,循环使用,避免反复销毁和分配 。
基础实现
最简单的对象池可以用一个 Queue 或 List 来管理。
using UnityEngine;
using System.Collections.Generic;
public class ObjectPool : MonoBehaviour{
public GameObject prefab;
public int initialSize = 10;
private Queue<GameObject> pool = new Queue<GameObject>();
void Start() {
for (int i = 0; i < initialSize; i++) {
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
pool.Enqueue(obj);
}
}
public GameObject Get() {
if (pool.Count > 0) {
GameObject obj = pool.Dequeue();
obj.SetActive(true);
return obj;
}
// 池子不够时可选择扩容
GameObject newObj = Instantiate(prefab);
return newObj;
}
public void Release(GameObject obj) {
obj.SetActive(false);
pool.Enqueue(obj);
}
}
使用时,可以通过 Get() 获取对象,使用完再调用 Release() 归还。
应用场景
-
子弹系统
射击类游戏子弹数量巨大,使用对象池能避免频繁GC。
-
特效播放
爆炸、击中特效往往短暂但数量多,适合对象池管理。
-
敌人或NPC生成
在波次制游戏中,敌人重复出现,适合通过对象池复用。
优化思路
-
分组管理
根据不同对象类型建立多个池,例如子弹池、特效池。
-
预扩容
在加载关卡时预先生成对象,避免运行中卡顿。
-
回收策略
对象池过大时,可以限制最大容量,超出部分销毁。
-
自动归还
对象本身可在逻辑结束后自动调用 Release(),避免遗忘。
实战案例:子弹系统
public class Bullet : MonoBehaviour{
private float lifeTime = 2f;
private float timer;
private ObjectPool pool;
public void Init(ObjectPool p) {
pool = p;
timer = 0f;
}
void Update() {
timer += Time.deltaTime;
if (timer >= lifeTime) {
pool.Release(gameObject);
}
}
}
发射子弹时:
GameObject bullet = bulletPool.Get();
bullet.transform.position = firePoint.position;
bullet.GetComponent<Bullet>().Init(bulletPool);
这样子弹生命周期结束时会自动回收,避免了手动管理的复杂性。
注意事项
-
对象池管理的对象不宜过于复杂,否则初始化成本过高。
-
在多人协作中要统一对象池接口,避免不同系统重复实现。
-
Unity自带的 Pooling 在UI系统中也有应用,例如 ScrollView 的元素复用,原理类似。
小结
对象池是Unity性能优化中最常见、最实用的技巧之一:
-
避免频繁的 Instantiate 与 Destroy;
-
适合高频、短生命周期的对象;
-
可通过扩容、分组和自动归还机制进一步优化。
合理使用对象池,可以显著减少GC带来的卡顿,提高游戏运行的流畅度。下一篇我们将介绍 事件系统与观察者模式 ,它能进一步降低模块间耦合。
