Commit efac0019 authored by Gerard Gascón's avatar Gerard Gascón
Browse files

feat: spawning particles with object pooling

parent 858e49e1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -112,3 +112,4 @@ MonoBehaviour:
  m_Name: 
  m_EditorClassIdentifier: 
  animator: {fileID: 1908639354391246343}
  particleAnimation: {fileID: 11400000, guid: 3aa2da34174b2354d94d7764f109d1c0, type: 2}
+3 −0
Original line number Diff line number Diff line
fileFormatVersion: 2
guid: a956b08a87cc495ca71443493064210d
timeCreated: 1713519317
 No newline at end of file
+5 −0
Original line number Diff line number Diff line
namespace Pooling {
	public interface IPooledObject {
		void OnObjectSpawn();
	}
}
 No newline at end of file
+3 −0
Original line number Diff line number Diff line
fileFormatVersion: 2
guid: 75e27a032d064219bd1f9314952bdbb8
timeCreated: 1713534220
 No newline at end of file
+152 −0
Original line number Diff line number Diff line
using System.Collections.Generic;
using UnityEngine;

namespace Pooling {
	public class Pooler : MonoBehaviour {
		private static Pooler _instance;

		public static Pooler Instance {
			get {
				if (_instance != null)
					return _instance;

				_instance = FindObjectOfType<Pooler>();
				if (_instance != null)
					return _instance;

				GameObject obj = new("[Object Pool]");
				_instance = obj.AddComponent<Pooler>();
				return _instance;
			}
		}

		private static List<GameObject> _tempList = new();

		private Dictionary<GameObject, List<GameObject>> _pooledObjects = new();
		private Dictionary<GameObject, GameObject> _spawnedObjects = new();

		public static void CreatePool<T>(T prefab, int initialPoolSize) where T : Component {
			CreatePool(prefab.gameObject, initialPoolSize);
		}

		public static void CreatePool(GameObject prefab, int initialPoolSize) {
			if (prefab == null || Instance._pooledObjects.ContainsKey(prefab))
				return;

			List<GameObject> list = new();
			Instance._pooledObjects.Add(prefab, list);

			if (initialPoolSize <= 0) return;

			bool active = prefab.activeSelf;
			prefab.SetActive(false);
			Transform parent = Instance.transform;
			while (list.Count < initialPoolSize) {
				GameObject obj = Instantiate(prefab, parent);
				list.Add(obj);
			}
			prefab.SetActive(active);
		}

		public static T Spawn<T>(T prefab, Transform parent, Vector3 position, Quaternion rotation)
			where T : Component =>
			Spawn(prefab.gameObject, parent, position, rotation).GetComponent<T>();

		public static T Spawn<T>(T prefab, Vector3 position, Quaternion rotation) where T : Component =>
			Spawn(prefab.gameObject, null, position, rotation).GetComponent<T>();

		public static T Spawn<T>(T prefab, Transform parent, Vector3 position) where T : Component =>
			Spawn(prefab.gameObject, parent, position, Quaternion.identity).GetComponent<T>();

		public static T Spawn<T>(T prefab, Vector3 position) where T : Component =>
			Spawn(prefab.gameObject, null, position, Quaternion.identity).GetComponent<T>();

		public static T Spawn<T>(T prefab, Transform parent) where T : Component =>
			Spawn(prefab.gameObject, parent, Vector3.zero, Quaternion.identity).GetComponent<T>();

		public static T Spawn<T>(T prefab) where T : Component =>
			Spawn(prefab.gameObject, null, Vector3.zero, Quaternion.identity).GetComponent<T>();

		public static GameObject Spawn(GameObject prefab, Transform parent, Vector3 position) =>
			Spawn(prefab, parent, position, Quaternion.identity);

		public static GameObject Spawn(GameObject prefab, Vector3 position, Quaternion rotation) =>
			Spawn(prefab, null, position, rotation);

		public static GameObject Spawn(GameObject prefab, Transform parent) =>
			Spawn(prefab, parent, Vector3.zero, Quaternion.identity);

		public static GameObject Spawn(GameObject prefab, Vector3 position) =>
			Spawn(prefab, null, position, Quaternion.identity);

		public static GameObject Spawn(GameObject prefab) =>
			Spawn(prefab, null, Vector3.zero, Quaternion.identity);

		public static GameObject Spawn(GameObject prefab, Transform parent, Vector3 position, Quaternion rotation) {
			List<GameObject> list;
			Transform trans;
			GameObject obj;

			if (Instance._pooledObjects.TryGetValue(prefab, out list)) {
				obj = null;
				if (list.Count > 0) {
					while (!obj && list.Count > 0) {
						obj = list[0];
						list.RemoveAt(0);
					}
					if (obj != null) {
						trans = obj.transform;
						trans.parent = parent;
						trans.localPosition = position;
						trans.localRotation = rotation;
						obj.SetActive(true);
						Instance._spawnedObjects.Add(obj, prefab);
						TryCallPooledObject(obj);
						return obj;
					}
				}

				obj = Instantiate(prefab);
				trans = obj.transform;
				trans.parent = parent;
				trans.localPosition = position;
				trans.localRotation = rotation;
				Instance._spawnedObjects.Add(obj, prefab);
				TryCallPooledObject(obj);
				return obj;
			}

			obj = Instantiate(prefab);
			trans = obj.transform;
			trans.parent = parent;
			trans.localPosition = position;
			trans.localRotation = rotation;
			TryCallPooledObject(obj);
			return obj;
		}

		private static void TryCallPooledObject(GameObject obj) {
			if(obj.TryGetComponent(out IPooledObject pooledObject))
				pooledObject.OnObjectSpawn();
		}

		public static void Recycle<T>(T obj) where T : Component {
			Recycle(obj.gameObject);
		}

		public static void Recycle(GameObject obj) {
			GameObject prefab;
			if (Instance._spawnedObjects.TryGetValue(obj, out prefab))
				Recycle(obj, prefab);
			else
				Destroy(obj);
		}

		private static void Recycle(GameObject obj, GameObject prefab) {
			Instance._pooledObjects[prefab].Add(obj);
			Instance._spawnedObjects.Remove(obj);
			obj.transform.parent = Instance.transform;
			obj.SetActive(false);
		}
	}
}
 No newline at end of file
Loading