Insanely huge initial commit

This commit is contained in:
2026-02-21 16:40:15 -08:00
parent 208d626100
commit f74c547a13
33825 changed files with 5213498 additions and 0 deletions

View File

@@ -0,0 +1,623 @@
using UnityEngine;
using System.Collections;
using MoreMountains.Tools;
using System;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
namespace MoreMountains.Tools
{
[Serializable]
/// <summary>
/// Multiple object pooler object.
/// </summary>
public class MMMultipleObjectPoolerObject
{
public GameObject GameObjectToPool;
public int PoolSize;
public bool PoolCanExpand = true;
public bool Enabled = true;
}
/// <summary>
/// The various methods you can pull objects from the pool with
/// </summary>
public enum MMPoolingMethods { OriginalOrder, OriginalOrderSequential, RandomBetweenObjects, RandomPoolSizeBased }
/// <summary>
/// This class allows you to have a pool of various objects to pool from.
/// </summary>
[AddComponentMenu("More Mountains/Tools/Object Pool/MMMultipleObjectPooler")]
public class MMMultipleObjectPooler : MMObjectPooler
{
/// the list of objects to pool
public List<MMMultipleObjectPoolerObject> Pool;
[MMInformation("A MultipleObjectPooler is a reserve of objects, to be used by a Spawner. When asked, it will return an object from the pool (ideally an inactive one) chosen based on the pooling method you've chosen.\n- OriginalOrder will spawn objects in the order you've set them in the inspector (from top to bottom)\n- OriginalOrderSequential will do the same, but will empty each pool before moving to the next object\n- RandomBetweenObjects will pick one object from the pool, at random, but ignoring its pool size, each object has equal chances to get picked\n- PoolSizeBased randomly choses one object from the pool, based on its pool size probability (the larger the pool size, the higher the chances it'll get picked)'...",MoreMountains.Tools.MMInformationAttribute.InformationType.Info,false)]
/// the chosen pooling method
public MMPoolingMethods PoolingMethod = MMPoolingMethods.RandomPoolSizeBased;
[MMInformation("If you set CanPoolSameObjectTwice to false, the Pooler will try to prevent the same object from being pooled twice to avoid repetition. This will only affect random pooling methods, not ordered pooling.",MoreMountains.Tools.MMInformationAttribute.InformationType.Info,false)]
/// whether or not the same object can be pooled twice in a row. If you set CanPoolSameObjectTwice to false, the Pooler will try to prevent the same object from being pooled twice to avoid repetition. This will only affect random pooling methods, not ordered pooling.
public bool CanPoolSameObjectTwice=true;
/// a unique name that should match on all MMMultipleObjectPoolers you want to use together
[MMCondition("MutualizeWaitingPools", true)]
public string MutualizedPoolName = "";
public virtual List<MMMultipleObjectPooler> Owner { get; set; }
private void OnDestroy() { Owner?.Remove(this); }
/// the actual object pool
protected GameObject _lastPooledObject;
protected int _currentIndex = 0;
protected int _currentIndexCounter = 0;
/// <summary>
/// Determines the name of the object pool.
/// </summary>
/// <returns>The object pool name.</returns>
protected override string DetermineObjectPoolName()
{
if ((MutualizedPoolName == null) || (MutualizedPoolName == ""))
{
return ("[MultipleObjectPooler] " + this.name);
}
else
{
return ("[MultipleObjectPooler] " + MutualizedPoolName);
}
}
/// <summary>
/// Fills the object pool with the amount of objects you specified in the inspector.
/// </summary>
public override void FillObjectPool()
{
if ((Pool == null) || (Pool.Count == 0))
{
return;
}
// we create a waiting pool, if one already exists, no need to fill anything
if (!CreateWaitingPool())
{
return;
}
// if there's only one item in the Pool, we force CanPoolSameObjectTwice to true
if (Pool.Count <= 1)
{
CanPoolSameObjectTwice=true;
}
bool stillObjectsToPool;
int[] poolSizes;
// if we're gonna pool in the original inspector order
switch (PoolingMethod)
{
case MMPoolingMethods.OriginalOrder:
stillObjectsToPool = true;
// we store our poolsizes in a temp array so it doesn't impact the inspector
poolSizes = new int[Pool.Count];
for (int i = 0; i < Pool.Count; i++)
{
poolSizes[i] = Pool[i].PoolSize;
}
// we go through our objects in the order they were in the inspector, and fill the pool while we find objects to add
while (stillObjectsToPool)
{
stillObjectsToPool = false;
for (int i = 0; i < Pool.Count; i++)
{
if (poolSizes[i] > 0)
{
AddOneObjectToThePool(Pool[i].GameObjectToPool);
poolSizes[i]--;
stillObjectsToPool = true;
}
}
}
break;
case MMPoolingMethods.OriginalOrderSequential:
// we store our poolsizes in a temp array so it doesn't impact the inspector
foreach (MMMultipleObjectPoolerObject pooledGameObject in Pool)
{
for (int i = 0; i < pooledGameObject.PoolSize ; i++ )
{
AddOneObjectToThePool(pooledGameObject.GameObjectToPool);
}
}
break;
default:
int k = 0;
// for each type of object specified in the inspector
foreach (MMMultipleObjectPoolerObject pooledGameObject in Pool)
{
// if there's no specified number of objects to pool for that type of object, we do nothing and exit
if (k > Pool.Count) { return; }
// we add, one by one, the number of objects of that type, as specified in the inspector
for (int j = 0; j < Pool[k].PoolSize; j++)
{
AddOneObjectToThePool(pooledGameObject.GameObjectToPool);
}
k++;
}
break;
}
}
/// <summary>
/// Adds one object of the specified type to the object pool.
/// </summary>
/// <returns>The object that just got added.</returns>
/// <param name="typeOfObject">The type of object to add to the pool.</param>
protected virtual GameObject AddOneObjectToThePool(GameObject typeOfObject)
{
if (typeOfObject == null)
{
return null;
}
bool initialStatus = typeOfObject.activeSelf;
typeOfObject.SetActive(false);
GameObject newGameObject = (GameObject)Instantiate(typeOfObject);
typeOfObject.SetActive(initialStatus);
SceneManager.MoveGameObjectToScene(newGameObject, this.gameObject.scene);
if (NestWaitingPool)
{
newGameObject.transform.SetParent(_waitingPool.transform);
}
newGameObject.name = typeOfObject.name;
_objectPool.PooledGameObjects.Add(newGameObject);
return newGameObject;
}
/// <summary>
/// Gets a random object from the pool.
/// </summary>
/// <returns>The pooled game object.</returns>
public override GameObject GetPooledGameObject()
{
GameObject pooledGameObject;
switch (PoolingMethod)
{
case MMPoolingMethods.OriginalOrder:
pooledGameObject = GetPooledGameObjectOriginalOrder();
break;
case MMPoolingMethods.RandomPoolSizeBased:
pooledGameObject = GetPooledGameObjectPoolSizeBased();
break;
case MMPoolingMethods.RandomBetweenObjects:
pooledGameObject = GetPooledGameObjectRandomBetweenObjects();
break;
case MMPoolingMethods.OriginalOrderSequential:
pooledGameObject = GetPooledGameObjectOriginalOrderSequential();
break;
default:
pooledGameObject = null;
break;
}
if (pooledGameObject!=null)
{
_lastPooledObject = pooledGameObject;
}
else
{
_lastPooledObject = null;
}
return pooledGameObject;
}
/// <summary>
/// Tries to find a gameobject in the pool according to the order the list has been setup in (one of each, no matter how big their respective pool sizes)
/// </summary>
/// <returns>The pooled game object original order.</returns>
protected virtual GameObject GetPooledGameObjectOriginalOrder()
{
int newIndex;
// if we've reached the end of our list, we start again from the beginning
if (_currentIndex >= Pool.Count)
{
ResetCurrentIndex ();
}
MMMultipleObjectPoolerObject searchedObject = GetPoolObject(Pool[_currentIndex].GameObjectToPool);
if (_currentIndex >= _objectPool.PooledGameObjects.Count) { return null; }
if (!searchedObject.Enabled) { _currentIndex++; return null; }
// if the object is already active, we need to find another one
if (_objectPool.PooledGameObjects[_currentIndex].gameObject.activeInHierarchy)
{
GameObject findObject = FindInactiveObject(_objectPool.PooledGameObjects[_currentIndex].gameObject.name,_objectPool.PooledGameObjects);
if (findObject != null)
{
_currentIndex++;
return findObject;
}
// if its pool can expand, we create a new one
if (searchedObject.PoolCanExpand)
{
_currentIndex++;
return AddOneObjectToThePool(searchedObject.GameObjectToPool);
}
else
{
// if it can't expand we return nothing
return null;
}
}
else
{
// if the object is inactive, we return it
newIndex = _currentIndex;
_currentIndex++;
return _objectPool.PooledGameObjects[newIndex];
}
}
protected int _currentCount = 0;
/// <summary>
/// Tries to find a gameobject in the pool according to the order the list has been setup in (one of each, no matter how big their respective pool sizes)
/// </summary>
/// <returns>The pooled game object original order.</returns>
protected virtual GameObject GetPooledGameObjectOriginalOrderSequential()
{
// if we've reached the end of our list, we start again from the beginning
if (_currentIndex >= Pool.Count)
{
_currentCount = 0;
ResetCurrentIndex ();
}
MMMultipleObjectPoolerObject searchedObject = GetPoolObject(Pool[_currentIndex].GameObjectToPool);
if (_currentIndex >= _objectPool.PooledGameObjects.Count) { return null; }
if (!searchedObject.Enabled) { _currentIndex++; _currentCount = 0; return null; }
// if the object is already active, we need to find another one
if (_objectPool.PooledGameObjects[_currentIndex].gameObject.activeInHierarchy)
{
GameObject findObject = FindInactiveObject(Pool[_currentIndex].GameObjectToPool.name, _objectPool.PooledGameObjects);
if (findObject != null)
{
_currentCount++;
OrderSequentialResetCounter(searchedObject);
return findObject;
}
// if its pool can expand, we create a new one
if (searchedObject.PoolCanExpand)
{
_currentCount++;
OrderSequentialResetCounter(searchedObject);
return AddOneObjectToThePool(searchedObject.GameObjectToPool);
}
else
{
// if it can't expand we return nothing
_currentIndex++;
_currentCount = 0;
return null;
}
}
else
{
// if the object is inactive, we return it
_currentCount++;
OrderSequentialResetCounter(searchedObject);
return _objectPool.PooledGameObjects[_currentIndex];
}
}
protected virtual void OrderSequentialResetCounter(MMMultipleObjectPoolerObject searchedObject)
{
if (_currentCount >= searchedObject.PoolSize)
{
_currentIndex++;
_currentCount = 0;
}
}
/// <summary>
/// Randomly choses one object from the pool, based on its pool size probability (the larger the pool size, the higher the chances it'll get picked)
/// </summary>
/// <returns>The pooled game object pool size based.</returns>
protected virtual GameObject GetPooledGameObjectPoolSizeBased()
{
// we get a random index
int randomIndex = UnityEngine.Random.Range(0, _objectPool.PooledGameObjects.Count);
int overflowCounter=0;
// we check to see if that object is enabled, if it's not we loop
while (!PoolObjectEnabled(_objectPool.PooledGameObjects[randomIndex]) && overflowCounter < _objectPool.PooledGameObjects.Count)
{
randomIndex = UnityEngine.Random.Range(0, _objectPool.PooledGameObjects.Count);
overflowCounter++;
}
if (!PoolObjectEnabled(_objectPool.PooledGameObjects[randomIndex]))
{
return null;
}
// if we can't pool the same object twice, we'll loop for a while to try and get another one
overflowCounter = 0;
while (!CanPoolSameObjectTwice
&& _objectPool.PooledGameObjects[randomIndex] == _lastPooledObject
&& overflowCounter < _objectPool.PooledGameObjects.Count)
{
randomIndex = UnityEngine.Random.Range(0, _objectPool.PooledGameObjects.Count);
overflowCounter++;
}
// if the item we've picked is active
if (_objectPool.PooledGameObjects[randomIndex].gameObject.activeInHierarchy)
{
// we try to find another inactive object of the same type
GameObject pulledObject = FindInactiveObject(_objectPool.PooledGameObjects[randomIndex].gameObject.name,_objectPool.PooledGameObjects);
if (pulledObject!=null)
{
return pulledObject;
}
else
{
// if we couldn't find an inactive object of this type, we see if it can expand
MMMultipleObjectPoolerObject searchedObject = GetPoolObject(_objectPool.PooledGameObjects[randomIndex].gameObject);
if (searchedObject==null)
{
return null;
}
// if the pool for this object is allowed to grow (this is set in the inspector if you're wondering)
if (searchedObject.PoolCanExpand)
{
return AddOneObjectToThePool(searchedObject.GameObjectToPool);
}
else
{
// if it's not allowed to grow, we return nothing.
return null;
}
}
}
else
{
// if the pool wasn't empty, we return the random object we've found.
return _objectPool.PooledGameObjects[randomIndex];
}
}
/// <summary>
/// Gets one object from the pool, at random, but ignoring its pool size, each object has equal chances to get picked
/// </summary>
/// <returns>The pooled game object random between objects.</returns>
protected virtual GameObject GetPooledGameObjectRandomBetweenObjects()
{
// we pick one of the objects in the original pool at random
int randomIndex = UnityEngine.Random.Range(0, Pool.Count);
int overflowCounter=0;
// if we can't pool the same object twice, we'll loop for a while to try and get another one
while (!CanPoolSameObjectTwice && Pool[randomIndex].GameObjectToPool == _lastPooledObject && overflowCounter < _objectPool.PooledGameObjects.Count )
{
randomIndex = UnityEngine.Random.Range(0, Pool.Count);
overflowCounter++;
}
int originalRandomIndex = randomIndex+1;
bool objectFound = false;
// while we haven't found an object to return, and while we haven't gone through all the different object types, we keep going
overflowCounter=0;
while (!objectFound
&& randomIndex != originalRandomIndex
&& overflowCounter < _objectPool.PooledGameObjects.Count)
{
// if our index is at the end, we reset it
if (randomIndex >= Pool.Count)
{
randomIndex=0;
}
if (!Pool[randomIndex].Enabled)
{
randomIndex++;
overflowCounter++;
continue;
}
// we try to find an inactive object of that type in the pool
GameObject newGameObject = FindInactiveObject(Pool[randomIndex].GameObjectToPool.name, _objectPool.PooledGameObjects);
if (newGameObject!=null)
{
objectFound=true;
return newGameObject;
}
else
{
// if there's none and if we can expand, we expand
if (Pool[randomIndex].PoolCanExpand)
{
return AddOneObjectToThePool(Pool[randomIndex].GameObjectToPool);
}
}
randomIndex++;
overflowCounter++;
}
return null;
}
protected string _tempSearchedName;
/// <summary>
/// Gets an object of the type at the specified index in the Pool.
/// Note that the whole point of this multiple object pooler is to abstract the various pools and handle
/// the picking based on the selected mode. If you plan on just picking from different pools yourself,
/// consider simply having multiple single object poolers.
/// </summary>
/// <param name="index"></param>
public virtual GameObject GetPooledGamObjectAtIndex(int index)
{
if ((index < 0) || (index >= Pool.Count))
{
return null;
}
_tempSearchedName = Pool[index].GameObjectToPool.name;
return GetPooledGameObjectOfType(_tempSearchedName);
}
/// <summary>
/// Gets an object of the specified name from the pool
/// Note that the whole point of this multiple object pooler is to abstract the various pools and handle
/// the picking based on the selected mode. If you plan on just picking from different pools yourself,
/// consider simply having multiple single object poolers.
/// </summary>
/// <returns>The pooled game object of type.</returns>
/// <param name="type">Type.</param>
public virtual GameObject GetPooledGameObjectOfType(string searchedName)
{
GameObject newObject = FindInactiveObject(searchedName,_objectPool.PooledGameObjects);
if (newObject!=null)
{
return newObject;
}
else
{
// if we've not returned the object, that means the pool is empty (at least it means it doesn't contain any object of that specific type)
// so if the pool is allowed to expand
GameObject searchedObject = FindObject(searchedName,_objectPool.PooledGameObjects);
if (searchedObject == null)
{
return null;
}
if (GetPoolObject(FindObject(searchedName,_objectPool.PooledGameObjects)).PoolCanExpand)
{
return AddOneObjectToThePool(searchedObject);
}
}
// if the pool was empty for that object and not allowed to expand, we return nothing.
return null;
}
/// <summary>
/// Finds an inactive object in the pool based on its name.
/// Returns null if no inactive object by that name were found in the pool
/// </summary>
/// <returns>The inactive object.</returns>
/// <param name="searchedName">Searched name.</param>
protected virtual GameObject FindInactiveObject(string searchedName, List<GameObject> list)
{
for (int i = 0; i < list.Count; i++)
{
// if we find an object inside the pool that matches the asked type
if (list[i].name.Equals(searchedName))
{
// and if that object is inactive right now
if (!list[i].gameObject.activeInHierarchy)
{
// we return it
return list[i];
}
}
}
return null;
}
protected virtual GameObject FindAnyInactiveObject(List<GameObject> list)
{
for (int i = 0; i < list.Count; i++)
{
// and if that object is inactive right now
if (!list[i].gameObject.activeInHierarchy)
{
// we return it
return list[i];
}
}
return null;
}
/// <summary>
/// Finds an object in the pool based on its name, active or inactive
/// Returns null if there's no object by that name in the pool
/// </summary>
/// <returns>The object.</returns>
/// <param name="searchedName">Searched name.</param>
protected virtual GameObject FindObject(string searchedName,List<GameObject> list)
{
for (int i = 0; i < list.Count; i++)
{
// if we find an object inside the pool that matches the asked type
if (list[i].name.Equals(searchedName))
{
// and if that object is inactive right now
return list[i];
}
}
return null;
}
/// <summary>
/// Returns (if it exists) the MultipleObjectPoolerObject from the original Pool based on a GameObject.
/// Note that this is name based.
/// </summary>
/// <returns>The pool object.</returns>
/// <param name="testedObject">Tested object.</param>
protected virtual MMMultipleObjectPoolerObject GetPoolObject(GameObject testedObject)
{
if (testedObject==null)
{
return null;
}
int i=0;
foreach(MMMultipleObjectPoolerObject poolerObject in Pool)
{
if (testedObject.name.Equals(poolerObject.GameObjectToPool.name))
{
return (poolerObject);
}
i++;
}
return null;
}
protected virtual bool PoolObjectEnabled(GameObject testedObject)
{
MMMultipleObjectPoolerObject searchedObject = GetPoolObject(testedObject);
if (searchedObject != null)
{
return searchedObject.Enabled;
}
else
{
return false;
}
}
public virtual void EnableObjects(string name,bool newStatus)
{
foreach(MMMultipleObjectPoolerObject poolerObject in Pool)
{
if (name.Equals(poolerObject.GameObjectToPool.name))
{
poolerObject.Enabled = newStatus;
}
}
}
public virtual void ResetCurrentIndex()
{
_currentIndex = 0;
_currentIndexCounter = 0;
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 73098ca8f002adc4f9debdbe47a78c9a
timeCreated: 1523900445
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace MoreMountains.Tools
{
public class MMObjectPool : MonoBehaviour
{
[MMReadOnly]
public List<GameObject> PooledGameObjects;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3148d0478f12644438359651f85a7a92
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,235 @@
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
namespace MoreMountains.Tools
{
/// <summary>
/// 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.
/// </summary>
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<MMObjectPool> _pools = new List<MMObjectPool>(_initialPoolsListCapacity);
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
protected static void InitializeStatics()
{
Instance = null;
}
/// <summary>
/// Adds a pooler to the static list if needed
/// </summary>
/// <param name="pool"></param>
public static void AddPool(MMObjectPool pool)
{
if (_pools == null)
{
_pools = new List<MMObjectPool>(_initialPoolsListCapacity);
}
if (!_pools.Contains(pool))
{
_pools.Add(pool);
}
}
/// <summary>
/// Removes a pooler from the static list
/// </summary>
/// <param name="pool"></param>
public static void RemovePool(MMObjectPool pool)
{
_pools?.Remove(pool);
}
/// <summary>
/// On awake we fill our object pool
/// </summary>
protected virtual void Awake()
{
Instance = this;
FillObjectPool();
}
/// <summary>
/// Creates the waiting pool or tries to reuse one if there's already one available
/// </summary>
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<MMObjectPool>();
_objectPool.PooledGameObjects = new List<GameObject>();
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<MMObjectPool>();
_objectPool.PooledGameObjects = new List<GameObject>();
ApplyNesting();
AddPool(_objectPool);
return true;
}
}
}
/// <summary>
/// Looks for an existing pooler for the same object, returns it if found, returns null otherwise
/// </summary>
/// <param name="objectToPool"></param>
/// <returns></returns>
public virtual MMObjectPool ExistingPool(string poolName)
{
if (_pools == null)
{
_pools = new List<MMObjectPool>(_initialPoolsListCapacity);
}
if (_pools.Count == 0)
{
var pools = FindObjectsOfType<MMObjectPool>();
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;
}
/// <summary>
/// If needed, nests the waiting pool under this object
/// </summary>
protected virtual void ApplyNesting()
{
if (NestWaitingPool && NestUnderThis && (_waitingPool != null))
{
_waitingPool.transform.SetParent(this.transform);
}
}
/// <summary>
/// Determines the name of the object pool.
/// </summary>
/// <returns>The object pool name.</returns>
protected virtual string DetermineObjectPoolName()
{
return ("[ObjectPooler] " + this.name);
}
/// <summary>
/// Implement this method to fill the pool with objects
/// </summary>
public virtual void FillObjectPool()
{
return ;
}
/// <summary>
/// Implement this method to return a gameobject
/// </summary>
/// <returns>The pooled game object.</returns>
public virtual GameObject GetPooledGameObject()
{
return null;
}
/// <summary>
/// Destroys the object pool
/// </summary>
public virtual void DestroyObjectPool()
{
if (_waitingPool != null)
{
Destroy(_waitingPool.gameObject);
}
}
/// <summary>
/// On enable we register to the scene loaded hook
/// </summary>
protected virtual void OnEnable()
{
if (!_onSceneLoadedRegistered)
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
}
/// <summary>
/// OnSceneLoaded we recreate
/// </summary>
/// <param name="scene"></param>
/// <param name="loadSceneMode"></param>
private void OnSceneLoaded(Scene scene, LoadSceneMode loadSceneMode)
{
if (this == null)
{
return;
}
if ((_objectPool == null) || (_waitingPool == null))
{
if (this != null)
{
FillObjectPool();
}
}
}
/// <summary>
/// On Destroy we remove ourselves from the list of poolers
/// </summary>
private void OnDestroy()
{
if ((_objectPool != null) && NestUnderThis)
{
RemovePool(_objectPool);
}
if (_onSceneLoadedRegistered)
{
SceneManager.sceneLoaded -= OnSceneLoaded;
_onSceneLoadedRegistered = false;
}
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 744b7d0770e56334f9ed2e0561c50cc3
timeCreated: 1523900445
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
using UnityEngine;
using UnityEngine.Events;
namespace MoreMountains.Tools
{
/// <summary>
/// Add this class to an object that you expect to pool from an objectPooler.
/// Note that these objects can't be destroyed by calling Destroy(), they'll just be set inactive (that's the whole point).
/// </summary>
[AddComponentMenu("More Mountains/Tools/Object Pool/MMPoolableObject")]
public class MMPoolableObject : MMObjectBounds
{
[Header("Events")]
public UnityEvent ExecuteOnEnable;
public UnityEvent ExecuteOnDisable;
public delegate void Events();
public event Events OnSpawnComplete;
[Header("Poolable Object")]
/// The life time, in seconds, of the object. If set to 0 it'll live forever, if set to any positive value it'll be set inactive after that time.
public float LifeTime = 0f;
/// <summary>
/// Turns the instance inactive, in order to eventually reuse it.
/// </summary>
public virtual void Destroy()
{
gameObject.SetActive(false);
}
/// <summary>
/// Called every frame
/// </summary>
protected virtual void Update()
{
}
/// <summary>
/// When the objects get enabled (usually after having been pooled from an ObjectPooler, we initiate its death countdown.
/// </summary>
protected virtual void OnEnable()
{
Size = GetBounds().extents * 2;
if (LifeTime > 0f)
{
Invoke("Destroy", LifeTime);
}
ExecuteOnEnable?.Invoke();
}
/// <summary>
/// When the object gets disabled (maybe it got out of bounds), we cancel its programmed death
/// </summary>
protected virtual void OnDisable()
{
ExecuteOnDisable?.Invoke();
CancelInvoke();
}
/// <summary>
/// Triggers the on spawn complete event
/// </summary>
public virtual void TriggerOnSpawnComplete()
{
OnSpawnComplete?.Invoke();
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 72de0b0360096ea41a18d17864ecb963
timeCreated: 1523900445
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,117 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
namespace MoreMountains.Tools
{
/// <summary>
/// A simple object pool outputting a single type of objects
/// </summary>
[AddComponentMenu("More Mountains/Tools/Object Pool/MMSimpleObjectPooler")]
public class MMSimpleObjectPooler : MMObjectPooler
{
/// the game object we'll instantiate
public GameObject GameObjectToPool;
/// the number of objects we'll add to the pool
public int PoolSize = 20;
/// if true, the pool will automatically add objects to the itself if needed
public bool PoolCanExpand = true;
public virtual List<MMSimpleObjectPooler> Owner { get; set; }
private void OnDestroy() { Owner?.Remove(this); }
/// <summary>
/// Fills the object pool with the gameobject type you've specified in the inspector
/// </summary>
public override void FillObjectPool()
{
if (GameObjectToPool == null)
{
return;
}
// if we've already created a pool, we exit
if ((_objectPool != null) && (_objectPool.PooledGameObjects.Count > PoolSize))
{
return;
}
CreateWaitingPool ();
int objectsToSpawn = PoolSize;
if (_objectPool != null)
{
objectsToSpawn -= _objectPool.PooledGameObjects.Count;
}
// we add to the pool the specified number of objects
for (int i = 0; i < objectsToSpawn; i++)
{
AddOneObjectToThePool ();
}
}
/// <summary>
/// Determines the name of the object pool.
/// </summary>
/// <returns>The object pool name.</returns>
protected override string DetermineObjectPoolName()
{
return ("[SimpleObjectPooler] " + GameObjectToPool.name);
}
/// <summary>
/// This method returns one inactive object from the pool
/// </summary>
/// <returns>The pooled game object.</returns>
public override GameObject GetPooledGameObject()
{
// we go through the pool looking for an inactive object
for (int i=0; i< _objectPool.PooledGameObjects.Count; i++)
{
if (!_objectPool.PooledGameObjects[i].gameObject.activeInHierarchy)
{
// if we find one, we return it
return _objectPool.PooledGameObjects[i];
}
}
// if we haven't found an inactive object (the pool is empty), and if we can extend it, we add one new object to the pool, and return it
if (PoolCanExpand)
{
return AddOneObjectToThePool();
}
// if the pool is empty and can't grow, we return nothing.
return null;
}
/// <summary>
/// Adds one object of the specified type (in the inspector) to the pool.
/// </summary>
/// <returns>The one object to the pool.</returns>
protected virtual GameObject AddOneObjectToThePool()
{
if (GameObjectToPool == null)
{
Debug.LogWarning("The "+gameObject.name+" ObjectPooler doesn't have any GameObjectToPool defined.", gameObject);
return null;
}
bool initialStatus = GameObjectToPool.activeSelf;
GameObjectToPool.SetActive(false);
GameObject newGameObject = (GameObject)Instantiate(GameObjectToPool);
GameObjectToPool.SetActive(initialStatus);
SceneManager.MoveGameObjectToScene(newGameObject, this.gameObject.scene);
if (NestWaitingPool)
{
newGameObject.transform.SetParent(_waitingPool.transform);
}
newGameObject.name = GameObjectToPool.name + "-" + _objectPool.PooledGameObjects.Count;
_objectPool.PooledGameObjects.Add(newGameObject);
return newGameObject;
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 0b7277539b95c0d45895792ecc99ce66
timeCreated: 1523900445
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: