Skip to content

Commit

Permalink
Changes to default parenting behaviour;
Browse files Browse the repository at this point in the history
Added ability to call .Pool<T> at editor time;
Performance improvements, and simplification of code;
Removed some PoolingExt, due to them introducing bad practices and potentially leading to slowdowns;
Updated Cubic Rain example;
  • Loading branch information
VergilUa committed Jan 31, 2021
1 parent a27e351 commit 8407252
Show file tree
Hide file tree
Showing 12 changed files with 773 additions and 362 deletions.
23 changes: 8 additions & 15 deletions Assets/_Code/Plugins/zPooling/GenericPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@
SOFTWARE.
*/
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Pooling {
/// <summary>
/// Generic pool for base pool operations
/// </summary>
public class GenericPool {
public Transform Parent;
public GameObject Prefab;

#region [Properties]
Expand Down Expand Up @@ -57,25 +55,16 @@ public class GenericPool {
/// <returns>Activated component</returns>
public T PoolFirst<T>() where T : MonoBehaviour {
IGenericPoolElement element = null;
// Grab first // LINQ -> Allocates
foreach (IGenericPoolElement ele in AvailableElements) {
element = ele;

// Get first, .First Allocates 32b
foreach (IGenericPoolElement el in AvailableElements) {
element = el;
break;
}

AvailableElements.Remove(element);
InUseElements.Add(element);

if (element == null) {
#if DEBUG
Debug.LogError("GenericPooler "
+ typeof(T)
+ ":: PoolFirst() - Something went wrong, non IGenericPoolElement in the AvailableElements");
#endif
return default;
}

return element as T;
}

Expand Down Expand Up @@ -138,5 +127,9 @@ public class GenericPool {

InUseElements.Clear();
}

public int GetTotalObjectCount() {
return AvailableElements.Count + InUseElements.Count;
}
}
}
219 changes: 36 additions & 183 deletions Assets/_Code/Plugins/zPooling/GenericPooler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
*/
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Pooling {
/// <summary>
Expand Down Expand Up @@ -49,6 +52,14 @@ public class GenericPooler : MonoBehaviour {
/// </summary>
/// <param name="prefab">GameObject prefab</param>
private T TakeFromPool<T>(GameObject prefab) where T : MonoBehaviour, IGenericPoolElement {
#if UNITY_EDITOR
if (!Application.isPlaying) {
GameObject go = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
go.TryGetComponent(out T component);

return component;
}
#endif
if (!PoolerLibrary.TryGetValue(prefab, out GenericPool manipulatedPool)) {
manipulatedPool = InstantiatePool(prefab);
}
Expand All @@ -69,182 +80,27 @@ public class GenericPooler : MonoBehaviour {
return returnedObject;
}

// Multiple methods overloads are created to improve performance. It's not necessary, but nice to have
// -- Vergil

/// <summary>
/// Instantiates object using pooling technique
/// </summary>
/// <param name="prefab">GameObject prefab</param>
public virtual T InstantiateFromPool<T>(GameObject prefab) where T : MonoBehaviour, IGenericPoolElement {
T returnedObject = TakeFromPool<T>(prefab);

returnedObject.Commission();
returnedObject.IsCommissioned = true;

return returnedObject;
}

// Multiple methods overloads are created to improve performance. It's not necessary, but nice to have
// -- Vergil

/// <summary>
/// Instantiates object using pooling technique
/// </summary>
/// <param name="prefab">GameObject prefab</param>
/// <param name="position">Position where it should be instantiated</param>
public virtual T InstantiateFromPool<T>(GameObject prefab, Vector3 position)
where T : MonoBehaviour, IGenericPoolElement {
T returnedObject = TakeFromPool<T>(prefab);
returnedObject.transform.position = position;

returnedObject.Commission();
returnedObject.IsCommissioned = true;
return returnedObject;
}

/// <summary>
/// Instantiates object using pooling technique
/// </summary>
/// <param name="prefab">GameObject prefab</param>
/// <param name="rotation">Rotation of instantiated transform</param>
public virtual T InstantiateFromPool<T>(GameObject prefab, Quaternion rotation)
where T : MonoBehaviour, IGenericPoolElement {
T returnedObject = TakeFromPool<T>(prefab);
returnedObject.transform.rotation = rotation;

returnedObject.Commission();
returnedObject.IsCommissioned = true;
return returnedObject;
}

/// <summary>
/// Instantiates object using pooling technique
/// </summary>
/// <param name="prefab">GameObject prefab</param>
/// <param name="position">Position where it should be instantiated</param>
/// <param name="rotation">Rotation of instantiated transform</param>
public virtual T InstantiateFromPool<T>(GameObject prefab, Vector3 position, Quaternion rotation)
where T : MonoBehaviour, IGenericPoolElement {
T returnedObject = TakeFromPool<T>(prefab);
returnedObject.transform.SetPositionAndRotation(position, rotation);

returnedObject.Commission();
returnedObject.IsCommissioned = true;

return returnedObject;
}

/// <summary>
/// Instantiates object using pooling technique
/// </summary>
/// <param name="prefab">GameObject prefab</param>
/// <param name="parent">Optional parent object</param>
/// <param name="worldPositionStays">Optional worldPositionStays for internal SetParent call</param>
public virtual T InstantiateFromPool<T>(GameObject prefab, Transform parent, bool worldPositionStays = true)
where T : MonoBehaviour, IGenericPoolElement {
T returnedObject = TakeFromPool<T>(prefab);
returnedObject.transform.SetParent(parent, worldPositionStays);

returnedObject.Commission();
returnedObject.IsCommissioned = true;

return returnedObject;
}

/// <summary>
/// Instantiates object using pooling technique
/// </summary>
/// <param name="prefab">GameObject prefab</param>
/// <param name="position">Position where it should be instantiated</param>
/// <param name="rotation">Rotation of instantiated transform</param>
/// <param name="parent">Optional parent object</param>
/// <param name="worldPositionStays">Optional worldPositionStays for internal SetParent call</param>
/// <returns>Instantiated object</returns>
public virtual T InstantiateFromPool<T>(GameObject prefab,
Vector3 position,
Quaternion rotation,
Transform parent,
bool worldPositionStays = true)
where T : MonoBehaviour, IGenericPoolElement {
T returnedObject = TakeFromPool<T>(prefab);

Transform trm = returnedObject.transform;
trm.SetParent(parent, worldPositionStays);
returnedObject.transform.SetPositionAndRotation(position, rotation);

returnedObject.Commission();
returnedObject.IsCommissioned = true;

return returnedObject;
}

/// <summary>
/// Instantiates object using pooling technique
/// </summary>
/// <param name="prefab">GameObject prefab</param>
/// <param name="position">Position where it should be instantiated</param>
/// <param name="parent">Optional parent object</param>
/// <param name="worldPositionStays">Optional worldPositionStays for internal SetParent call</param>
/// <returns>Instantiated object</returns>
public virtual T InstantiateFromPool<T>(GameObject prefab,
Vector3 position,
Transform parent,
bool worldPositionStays = true)
where T : MonoBehaviour, IGenericPoolElement {
T returnedObject = TakeFromPool<T>(prefab);

Transform trm = returnedObject.transform;
trm.SetParent(parent, worldPositionStays);
trm.position = position;

returnedObject.Commission();
returnedObject.IsCommissioned = true;

return returnedObject;
}

/// <summary>
/// Instantiates object using pooling technique
/// </summary>
/// <param name="prefab">GameObject prefab</param>
/// <param name="rotation">Rotation of instantiated transform</param>
/// <param name="parent">Optional parent object</param>
/// <param name="worldPositionStays">Optional worldPositionStays for internal SetParent call</param>
/// <returns>Instantiated object</returns>
public virtual T InstantiateFromPool<T>(GameObject prefab,
Quaternion rotation,
Transform parent,
bool worldPositionStays = true)
where T : MonoBehaviour, IGenericPoolElement {
T returnedObject = TakeFromPool<T>(prefab);

Transform trm = returnedObject.transform;
trm.SetParent(parent, worldPositionStays);
trm.rotation = rotation;

returnedObject.Commission();
returnedObject.IsCommissioned = true;

return returnedObject;
}

#endregion

/// <summary>
/// Instantiates an actual pool object to contain data about the pool
/// </summary>
protected GenericPool InstantiatePool(GameObject prefab) {
GenericPool pool = new GenericPool {Prefab = prefab};

GameObject poolParentGO = new GameObject();
#if UNITY_EDITOR
poolParentGO.name = prefab.name + " (Elements)";
#endif
Transform poolParentTrm = poolParentGO.transform;
poolParentTrm.SetParent(transform);
pool.Parent = poolParentTrm;

PoolerLibrary.Add(prefab, pool);
HashReference.Add(pool.GetHashCode(), pool);
return pool;
Expand All @@ -253,8 +109,6 @@ public virtual T InstantiateFromPool<T>(GameObject prefab, Transform parent, boo
/// <summary>
/// Obtains available element or instantiates a new one
/// </summary>
/// <param name="pool"></param>
/// <returns></returns>
protected virtual T ObtainElement<T>(GenericPool pool) where T : MonoBehaviour {
if (pool.HasAvailableElements) {
return pool.PoolFirst<T>();
Expand All @@ -270,31 +124,25 @@ public virtual T InstantiateFromPool<T>(GameObject prefab, Transform parent, boo
/// </summary>
/// <returns>Instantiated object of prefab</returns>
protected virtual T UnityInstantiate<T>(GenericPool pool) where T : MonoBehaviour {
GameObject pooledObject = Instantiate(pool.Prefab, pool.Parent);
GameObject pooledObject = Instantiate(pool.Prefab);
#if UNITY_EDITOR && DEBUG_ZPOOLING
pooledObject.name = pool.Prefab.name + " " + pool.TotalSpawned;
pool.TotalSpawned++;
#endif
if (pooledObject != null) {
// Adding to the pool as instance of generic pool element
IGenericPoolElement element = pooledObject.GetComponent<IGenericPoolElement>()
?? pooledObject.GetComponentInChildren<IGenericPoolElement>();
if (element != null) {
pool.AddToPool(element);
OnUnityInstantiatePostProcess(element);
}
// Adding to the pool as instance of generic pool element
if (pooledObject.TryGetComponent(out IGenericPoolElement element)) {
pool.AddToPool(element);
OnUnityInstantiatePostProcess(element);
}
#if DEBUG
else {
Debug.LogError("Unable to find component ("
+ typeof(T)
+ ") on generic pool element instance - "
+ pooledObject);
}
#endif
return pooledObject.GetComponent<T>();
else {
Debug.LogError("Unable to find component ("
+ typeof(T)
+ ") on generic pool element instance - "
+ pooledObject);
}

return null;
#endif
return element as T;
}

/// <summary>
Expand Down Expand Up @@ -331,7 +179,7 @@ public virtual T InstantiateFromPool<T>(GameObject prefab, Transform parent, boo
/// <summary>
/// Spawns N of objects and decommissions them for future use
/// </summary>
private void InitializeObjects(GameObject prefab, int objCount, Vector3 prewarmPos, bool isAuto) {
public void InitializeObjects(GameObject prefab, int objCount, Vector3 prewarmPos, bool isAuto) {
if (!PoolerLibrary.TryGetValue(prefab, out GenericPool manipulatedPool)) {
manipulatedPool = InstantiatePool(prefab);
}
Expand All @@ -343,7 +191,8 @@ public virtual T InstantiateFromPool<T>(GameObject prefab, Transform parent, boo

instance.transform.position = prewarmPos;

IGenericPoolElement element = instance.GetComponent<IGenericPoolElement>();
instance.TryGetComponent(out IGenericPoolElement element);
element.IsCommissioned = false;
element.UsesAutoPool = isAuto;
element.PoolRef = hash;
element.ReturnToPool();
Expand All @@ -364,10 +213,6 @@ public virtual T InstantiateFromPool<T>(GameObject prefab, Transform parent, boo
}
#endif

Transform genericObjTrm = element.transform;
Transform genericPoolParent = genericPool.Parent;
genericObjTrm.SetParent(genericPoolParent);

genericPool.ReturnToPool(element);
}

Expand All @@ -388,5 +233,13 @@ public virtual T InstantiateFromPool<T>(GameObject prefab, Transform parent, boo
pool.ForceDecommissionAll();
}
}

public int GetTotalObjectCount(GameObject prefab) {
if (!PoolerLibrary.TryGetValue(prefab, out GenericPool pool)){
return 0;
}

return pool.GetTotalObjectCount();
}
}
}
Loading

0 comments on commit 8407252

Please sign in to comment.