using System; using System.Collections.Generic; using Magisterka.BulletHell; using UnityEngine; namespace Magisterka.BulletHell { /// /// Runtime pool that keeps huge bullet counts without constant allocations. /// public class BulletPool : MonoBehaviour { [SerializeField] private Color bulletColor = Color.white; [SerializeField] private Faction faction = Faction.Player; [SerializeField] private int warmCapacity = 64; private readonly Queue _pool = new Queue(); private readonly HashSet _liveBullets = new HashSet(); private Transform _poolRoot; public Color BulletColor => bulletColor; public Faction OwnerFaction => faction; public static BulletPool Create(Transform parent, string poolName, Color color, Faction ownerFaction, int warmCount) { if (parent == null) throw new ArgumentNullException(nameof(parent)); var go = new GameObject(poolName); go.transform.SetParent(parent, false); var pool = go.AddComponent(); pool.Initialize(color, ownerFaction, warmCount); return pool; } private void Initialize(Color color, Faction ownerFaction, int warmCount) { bulletColor = color; faction = ownerFaction; warmCapacity = Mathf.Max(0, warmCount); _poolRoot = new GameObject("Inactive" + name).transform; _poolRoot.SetParent(transform, false); for (int i = 0; i < warmCapacity; i++) { var bullet = Bullet.Create(this, bulletColor, faction); Return(bullet); } } public Bullet Spawn(Vector2 position, Vector2 direction, float speed, float damage) { Bullet bullet = _pool.Count > 0 ? _pool.Dequeue() : Bullet.Create(this, bulletColor, faction); _liveBullets.Add(bullet); bullet.transform.SetParent(null, false); bullet.gameObject.SetActive(true); bullet.transform.position = position; bullet.Configure(direction, speed, damage, faction); return bullet; } public void Return(Bullet bullet) { if (bullet == null) return; bullet.gameObject.SetActive(false); bullet.transform.SetParent(_poolRoot, false); _pool.Enqueue(bullet); _liveBullets.Remove(bullet); } public void ClearLiveBullets() { if (_liveBullets.Count == 0) return; foreach (var bullet in _liveBullets) { if (bullet != null) { bullet.gameObject.SetActive(false); bullet.transform.SetParent(_poolRoot, false); _pool.Enqueue(bullet); } } _liveBullets.Clear(); } } }