Object Pooling
Instantiate and Destroy are expensive, especially for things spawned constantly like bullets or particle effects. Object pooling reuses a fixed set of objects instead of constantly creating and destroying them.
using System.Collections.Generic;
using UnityEngine;
public class BulletPool : MonoBehaviour
{
public GameObject bulletPrefab;
public int poolSize = 20;
Queue<GameObject> pool = new Queue<GameObject>();
void Awake()
{
for (int i = 0; i < poolSize; i++)
{
GameObject bullet = Instantiate(bulletPrefab);
bullet.SetActive(false);
pool.Enqueue(bullet);
}
}
public GameObject Get()
{
GameObject bullet = pool.Count > 0 ? pool.Dequeue() : Instantiate(bulletPrefab);
bullet.SetActive(true);
return bullet;
}
public void Release(GameObject bullet)
{
bullet.SetActive(false);
pool.Enqueue(bullet);
}
}
The pieces
- Every object the pool will hand out is created once, up front, and disabled.
Get()hands out a disabled object (reactivating it) instead of instantiating a new one,Release()deactivates and returns it to the pool instead of destroying it.- A
Queue<T>is a natural fit,Enqueueadds to the back,Dequeueremoves from the front, first in, first out. - Falling back to
InstantiateinsideGet()when the pool is empty avoids ever running out, at the cost of an occasional allocation.
Why it matters
Instantiate/Destroy allocate and garbage-collect memory, doing that dozens of times per second (every bullet fired, every hit particle) causes frame-rate stutters as the garbage collector kicks in. Reusing objects avoids that churn entirely. Unity also ships a built-in UnityEngine.Pool.ObjectPool<T> that implements this same pattern for you.