Last active
July 16, 2020 02:36
-
-
Save stillwwater/7b9d08f18c7f9923094c32f31dca75e8 to your computer and use it in GitHub Desktop.
Better GameObject Pooling In Unity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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