using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.SceneManagement; namespace MoreMountains.Tools { /// /// A base class, meant to be extended depending on the use (simple, multiple object pooler), and used as an interface by the spawners. /// Still handles common stuff like singleton and initialization on start(). /// DO NOT add this class to a prefab, nothing would happen. Instead, add SimpleObjectPooler or MultipleObjectPooler. /// public abstract class MMObjectPooler : MonoBehaviour { /// singleton pattern public static MMObjectPooler Instance; /// if this is true, the pool will try not to create a new waiting pool if it finds one with the same name. public bool MutualizeWaitingPools = false; /// if this is true, all waiting and active objects will be regrouped under an empty game object. Otherwise they'll just be at top level in the hierarchy public bool NestWaitingPool = true; /// if this is true, the waiting pool will be nested under this object [MMCondition("NestWaitingPool", true)] public bool NestUnderThis = false; /// this object is just used to group the pooled objects protected GameObject _waitingPool = null; protected MMObjectPool _objectPool; protected const int _initialPoolsListCapacity = 5; protected bool _onSceneLoadedRegistered = false; public static List _pools = new List(_initialPoolsListCapacity); /// /// Adds a pooler to the static list if needed /// /// public static void AddPool(MMObjectPool pool) { if (_pools == null) { _pools = new List(_initialPoolsListCapacity); } if (!_pools.Contains(pool)) { _pools.Add(pool); } } /// /// Removes a pooler from the static list /// /// public static void RemovePool(MMObjectPool pool) { _pools?.Remove(pool); } /// /// On awake we fill our object pool /// protected virtual void Awake() { Instance = this; FillObjectPool(); } /// /// Creates the waiting pool or tries to reuse one if there's already one available /// protected virtual bool CreateWaitingPool() { if (!MutualizeWaitingPools) { // we create a container that will hold all the instances we create _waitingPool = new GameObject(DetermineObjectPoolName()); SceneManager.MoveGameObjectToScene(_waitingPool, this.gameObject.scene); _objectPool = _waitingPool.AddComponent(); _objectPool.PooledGameObjects = new List(); ApplyNesting(); return true; } else { MMObjectPool objectPool = ExistingPool(DetermineObjectPoolName()); if (objectPool != null) { _objectPool = objectPool; _waitingPool = objectPool.gameObject; return false; } else { _waitingPool = new GameObject(DetermineObjectPoolName()); SceneManager.MoveGameObjectToScene(_waitingPool, this.gameObject.scene); _objectPool = _waitingPool.AddComponent(); _objectPool.PooledGameObjects = new List(); ApplyNesting(); AddPool(_objectPool); return true; } } } /// /// Looks for an existing pooler for the same object, returns it if found, returns null otherwise /// /// /// public virtual MMObjectPool ExistingPool(string poolName) { if (_pools == null) { _pools = new List(_initialPoolsListCapacity); } if (_pools.Count == 0) { var pools = FindObjectsOfType(); if (pools.Length > 0) { _pools.AddRange(pools); } } foreach (MMObjectPool pool in _pools) { if ((pool != null) && (pool.name == poolName)/* && (pool.gameObject.scene == this.gameObject.scene)*/) { return pool; } } return null; } /// /// If needed, nests the waiting pool under this object /// protected virtual void ApplyNesting() { if (NestWaitingPool && NestUnderThis && (_waitingPool != null)) { _waitingPool.transform.SetParent(this.transform); } } /// /// Determines the name of the object pool. /// /// The object pool name. protected virtual string DetermineObjectPoolName() { return ("[ObjectPooler] " + this.name); } /// /// Implement this method to fill the pool with objects /// public virtual void FillObjectPool() { return ; } /// /// Implement this method to return a gameobject /// /// The pooled game object. public virtual GameObject GetPooledGameObject() { return null; } /// /// Destroys the object pool /// public virtual void DestroyObjectPool() { if (_waitingPool != null) { Destroy(_waitingPool.gameObject); } } /// /// On enable we register to the scene loaded hook /// protected virtual void OnEnable() { if (!_onSceneLoadedRegistered) { SceneManager.sceneLoaded += OnSceneLoaded; } } /// /// OnSceneLoaded we recreate /// /// /// private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode) { if (this == null) { return; } if ((_objectPool == null) || (_waitingPool == null)) { if (this != null) { FillObjectPool(); } } } /// /// On Destroy we remove ourselves from the list of poolers /// private void OnDestroy() { if ((_objectPool != null) && NestUnderThis) { RemovePool(_objectPool); } if (_onSceneLoadedRegistered) { SceneManager.sceneLoaded -= OnSceneLoaded; _onSceneLoadedRegistered = false; } } } }