Skip to content

Instantly share code, notes, and snippets.

@stillwwater
Last active July 16, 2020 02:36
Show Gist options
  • Select an option

  • Save stillwwater/7b9d08f18c7f9923094c32f31dca75e8 to your computer and use it in GitHub Desktop.

Select an option

Save stillwwater/7b9d08f18c7f9923094c32f31dca75e8 to your computer and use it in GitHub Desktop.
Better GameObject Pooling In Unity
using System.Collections.Generic;
using UnityEngine;
class Pool<T> where T : Component
{
readonly List<T> pool;
readonly T prefab;
readonly Transform parent;
int id;
public Pool(T prefab, Transform parent = null) {
Debug.Assert(prefab != null);
this.parent = parent;
this.prefab = prefab;
this.pool = new List<T>();
}
public int Count => pool.Count;
// Increases number of objects in the pool by an amount
// that's greater or equal to capacity. If capacity is
// less than or equal to `pool.Count` this method does nothing.
public void Reserve(int capacity) {
int delta = capacity - pool.Count;
if (delta > 0) {
Grow(delta);
}
}
// Resizes the pool to contain exactly `count` objects.
public void Resize(int count) {
if (count > pool.Count)
Grow(count - pool.Count);
else if (count < pool.Count)
Shrink(pool.Count - count);
}
// Retrieves an instance from the pool. If the pool is empty it
// will instantiate and new object and return it.
public T Retrieve() {
if (pool.Count == 0) {
// Increase number of elements
Grow(1);
}
var go = pool[pool.Count - 1];
pool.RemoveAt(pool.Count - 1);
go.gameObject.SetActive(true);
return go;
}
// Returns an object back to the pool to be reused.
public void Free(T go) {
Debug.Assert(go != null);
go.gameObject.SetActive(false);
pool.Add(go);
}
// Destroys all objects in the pool.
public void Clear() {
foreach (var go in pool) {
GameObject.Destroy(go.gameObject);
}
pool.Clear();
}
void Grow(int amount) {
for (int i = 0; i < amount; i++) {
var go = GameObject.Instantiate(prefab, parent);
go.name = prefab.name + (id++).ToString("x4");
go.gameObject.SetActive(false);
pool.Add(go);
}
}
void Shrink(int amount) {
Debug.Assert(amount <= pool.Count);
for (int i = 0; i < amount; i++) {
var go = pool[pool.Count - 1];
pool.RemoveAt(pool.Count - 1);
GameObject.Destroy(go.gameObject);
}
}
}
// Example usage for Pool<T>
using System.Collections;
using UnityEngine;
class Spawner : MonoBehaviour
{
[SerializeField] Rigidbody prefab = null;
[SerializeField] [Range(0f, 10f)] float lifetime = 5f;
[SerializeField] int count = 300;
Pool<Rigidbody> pool;
void Start() {
pool = new Pool<Rigidbody>(prefab, transform);
pool.Reserve(count);
// I do not advocate creating 300 coroutines...
// this is just a bit of fun :P
for (int i = 0; i < count; i++)
StartCoroutine(Spawn(i/(float)count + i/lifetime));
}
IEnumerator Spawn(float start) {
yield return new WaitForSeconds(start);
var wait = new WaitForSeconds(lifetime);
while (true) {
// Get a reference to a RigidBody component
var rb = pool.Retrieve();
// Reset the transform since the object returned
// might be in some unknown state.
var tf = rb.gameObject.transform;
tf.position = transform.position;
tf.rotation = Quaternion.identity;
rb.velocity = new Vector3 {
x = Random.Range(-0.1f, 0.1f),
y = Random.Range(5f, 10f),
z = Random.Range(-0.1f, 0.1f),
};
yield return wait;
// Return the component to the pool so it can be reused
pool.Free(rb);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment