Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save unitycoder/616cce4e253ac2ad91ff45c24fd24591 to your computer and use it in GitHub Desktop.
Save unitycoder/616cce4e253ac2ad91ff45c24fd24591 to your computer and use it in GitHub Desktop.
using CodeSmile.Components.Registry;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace CodeSmile.Components.Pool
{
[DisallowMultipleComponent]
public sealed class PrefabPool : MonoBehaviour
{
[SerializeField] [Range(10, 10000)] private Int32 m_InitialCapacity = 100;
[SerializeField] [Range(10, 10000)] private Int32 m_MaxCapacity = 10000;
private readonly Dictionary<Int32, PrefabInstancePool> m_Pools = new();
private void Awake() => ComponentsRegistry.Set(this);
public GameObject GetInstance(GameObject prefab)
{
var pool = GetOrCreatePool(prefab);
return pool.GetInstance();
}
public void ReleaseInstance(GameObject prefab, GameObject instance)
{
var pool = GetOrCreatePool(prefab);
pool.ReleaseInstance(instance);
}
public GameObject GetInstance(GameObject prefab, Vector3 position, Quaternion rotation)
{
var pool = GetOrCreatePool(prefab);
var instance = pool.GetInstance();
instance.transform.SetPositionAndRotation(position, rotation);
return instance;
}
public PrefabInstancePool CreatePool(GameObject prefab, Int32 initialCapacity, Int32 maxCapacity)
{
var pool = GetPool(prefab);
if (pool != null)
DisposePool(prefab);
initialCapacity = initialCapacity <= 0 ? m_InitialCapacity : initialCapacity;
maxCapacity = maxCapacity <= 0 ? m_MaxCapacity : maxCapacity;
CreatePool(prefab, prefab.GetInstanceID(), initialCapacity, maxCapacity);
return GetPool(prefab);
}
public void ClearPool(GameObject prefab)
{
var pool = GetOrCreatePool(prefab);
pool.Clear();
}
public void DisposePool(GameObject prefab)
{
var pool = GetOrCreatePool(prefab);
m_Pools[prefab.GetInstanceID()] = null;
pool.Clear();
Destroy(pool.Container);
}
public PrefabInstancePool GetPool(GameObject prefab) => m_Pools[prefab.GetInstanceID()];
public PrefabInstancePool GetOrCreatePool(GameObject prefab)
{
var prefabId = prefab.GetInstanceID();
if (m_Pools.ContainsKey(prefabId) == false)
CreatePool(prefab, prefabId, m_InitialCapacity, m_MaxCapacity);
return m_Pools[prefabId];
}
private void CreatePool(GameObject prefab, Int32 prefabId, Int32 initialCapacity, Int32 maxCapacity) =>
m_Pools[prefabId] = new PrefabInstancePool(prefab, transform, initialCapacity, maxCapacity);
#if UNITY_EDITOR
[Header("Debug")]
[Tooltip("Updates container names frequently with pool statistics. Editor-only.")]
[SerializeField] private Boolean m_ShowPoolStats;
[SerializeField] [Range(0.05f, 1f)] private Single m_StatsUpdateFrequency = 0.2f;
private void Start() => StartCoroutine(UpdatePoolNames());
private IEnumerator UpdatePoolNames()
{
while (true)
{
yield return new WaitForSeconds(m_StatsUpdateFrequency);
var activeTotal = 0;
var inactiveTotal = 0;
var allTotal = 0;
if (m_ShowPoolStats)
{
foreach (var pool in m_Pools.Values)
{
var active = pool.CountActive;
var inactive = pool.CountInactive;
var all = pool.CountAll;
pool.Container.name = $"{pool.Prefab.name} (Active: {active}, Inactive: {inactive}, Total: {all})";
activeTotal += active;
inactiveTotal += inactive;
allTotal += all;
}
name = $"{nameof(PrefabPool)} (Active: {activeTotal}, Inactive: {inactiveTotal}, Total: {allTotal})";
}
}
}
#endif
}
}
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.Pool;
using Object = UnityEngine.Object;
namespace CodeSmile.Components.Pool
{
public sealed class PrefabInstancePool
{
private readonly GameObject m_Prefab;
private readonly Transform m_Container;
private readonly ObjectPool<GameObject> m_Pool;
public GameObject Prefab => m_Prefab;
public Transform Container => m_Container;
public Int32 CountActive => m_Pool.CountActive;
public Int32 CountInactive => m_Pool.CountInactive;
public Int32 CountAll => m_Pool.CountAll;
public PrefabInstancePool(GameObject prefab, Transform parent, Int32 initialCapacity = 100,
Int32 maximumCapacity = 10000)
{
if (prefab == null)
throw new ArgumentNullException(nameof(prefab));
m_Prefab = prefab;
m_Container = new GameObject($"{prefab.name} Instances").transform;
m_Container.parent = parent;
m_Pool = new ObjectPool<GameObject>(OnCreate, OnGet, OnRelease, OnDestroy, true, initialCapacity,
maximumCapacity);
}
public GameObject GetInstance() => m_Pool.Get();
public void ReleaseInstance(GameObject go) => m_Pool.Release(go);
public void Clear() => m_Pool.Clear();
private GameObject OnCreate() => Object.Instantiate(m_Prefab, m_Container);
private void OnGet(GameObject go) => go.SetActive(true);
private void OnRelease(GameObject go) => go.SetActive(false);
private void OnDestroy(GameObject go) {}
}
}
using UnityEditor;
using UnityEngine;
namespace CodeSmile.Components.Pool
{
[DisallowMultipleComponent]
internal sealed class AutoReleasePooledObject : MonoBehaviour
{
internal PrefabInstancePool Pool { get; set; }
private void OnDisable() => Pool.ReleaseInstance(gameObject);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment