using UnityEngine; using System.Collections.Generic; public static class UniStormPool { const int DEFAULT_POOL_SIZE = 3; /// /// The Pool class represents the pool for a particular prefab. /// class Pool { int nextId = 1; Stack inactive; // The prefab that we are pooling GameObject prefab; // Constructor public Pool(GameObject prefab, int initialQty) { this.prefab = prefab; inactive = new Stack(initialQty); } // Spawn an object from our pool public GameObject Spawn(Vector3 pos, Quaternion rot) { GameObject obj; if (inactive.Count == 0) { obj = (GameObject)GameObject.Instantiate(prefab, pos, rot); obj.name = prefab.name + " (" + (nextId++) + ")"; obj.AddComponent().myPool = this; } else { // Grab the last object in the inactive array obj = inactive.Pop(); if (obj == null) { return Spawn(pos, rot); } } obj.transform.position = pos; obj.transform.rotation = rot; obj.SetActive(true); return obj; } // Return an object to the inactive pool. public void Despawn(GameObject obj) { obj.SetActive(false); inactive.Push(obj); } } /// /// Added to freshly instantiated objects, so we can link back /// to the correct pool on despawn. /// class PoolMember : MonoBehaviour { public Pool myPool; } // All of our pools static Dictionary pools; /// /// Initialize our dictionary. /// static void Init(GameObject prefab = null, int qty = DEFAULT_POOL_SIZE) { if (pools == null) { pools = new Dictionary(); } if (prefab != null && pools.ContainsKey(prefab) == false) { pools[prefab] = new Pool(prefab, qty); } } /// /// If you want to preload a few copies of an object at the start /// of a scene, you can use this. Really not needed unless you're /// going to go from zero instances to 100+ very quickly. /// Could technically be optimized more, but in practice the /// Spawn/Despawn sequence is going to be pretty darn quick and /// this avoids code duplication. /// static public void Preload(GameObject prefab, int qty = 1) { Init(prefab, qty); // Make an array to grab the objects we're about to pre-spawn. GameObject[] obs = new GameObject[qty]; for (int i = 0; i < qty; i++) { obs[i] = Spawn(prefab, Vector3.zero, Quaternion.identity); } // Now despawn them all. for (int i = 0; i < qty; i++) { Despawn(obs[i]); } } /// /// Spawns a copy of the specified prefab (instantiating one if required). /// NOTE: Remember that Awake() or Start() will only run on the very first /// spawn and that member variables won't get reset. OnEnable will run /// after spawning -- but remember that toggling IsActive will also /// call that function. /// static public GameObject Spawn(GameObject prefab, Vector3 pos, Quaternion rot) { Init(prefab); return pools[prefab].Spawn(pos, rot); } /// /// Despawn the specified gameobject back into its pool. /// static public void Despawn(GameObject obj) { PoolMember pm = obj.GetComponent(); if (pm == null) { Debug.Log("Object '" + obj.name + "' wasn't spawned from a pool. Destroying it instead."); GameObject.Destroy(obj); } else { pm.myPool.Despawn(obj); } } }