using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace TyphoonPool { /// /// 池 /// [AddComponentMenu("")] public class Pool : MonoBehaviour { //池ID计数器 private static ulong _poolIDCounter = 0; //池对象ID计数器 private static ulong _objectIDCounter = 0; #if UNITY_EDITOR [InitializeOnEnterPlayMode] private static void OnEnterPlayMode() { _poolIDCounter = 0; _objectIDCounter = 0; } #endif // 池对象的生成代理 internal Func CreateFunc; // 池对象ID public ulong PoolID { get; internal set; } //空闲对象 internal Stack IdleObjects = new Stack(); //空闲ID internal HashSet IdleIDs = new HashSet(); //所有池对象 internal Dictionary Map = new Dictionary(); //获取Map迭代器 public Dictionary.Enumerator MapEnumerator => Map.GetEnumerator(); public void GetStatus(out int total, out int busyCount) { total = Map.Count; busyCount = 0; foreach (var pair in Map) { if (pair.Value != null && pair.Value.PoolObjectOperation.IsBusy) { busyCount += 1; } } } //加载时是否不摧毁 public bool IsNeverDestroyInLoad { get; private set; } /// /// 请通过Pool.CreatePool创建池 /// private Pool() { } /// /// 创建池(方式1) /// /// 池对象构造方法 /// 名称 /// 是否不销毁(池对象gameobject同样适用) /// internal static Pool Internal_CreatePool(Func func, string poolName = null, bool neverDestroyInLoad = false) { var poolID = _poolIDCounter += 1; var objName = poolName ?? $"Pool-{poolID}"; var obj = new GameObject(objName); var result = obj.AddComponent(); result.CreateFunc = func; result.PoolID = poolID; result.IsNeverDestroyInLoad = neverDestroyInLoad; if (neverDestroyInLoad) { DontDestroyOnLoad(obj); } PoolManager.AddPool(result); return result; } /// /// 创建池(方式2) /// /// 池对象预制物 /// 名称 /// 是否不销毁(池对象gameObject同样适用) /// PoolObject子类 /// internal static Pool Internal_CreatePool(GameObject prefab, string poolName = null, bool neverDestroyInLoad = false) where T : Component, IPoolObject { return Internal_CreatePool(() => { var clone = Instantiate(prefab); var result = clone.GetComponent(); if (result == null) { result = clone.AddComponent(); } return result; }, poolName, neverDestroyInLoad); } private IPoolObject CreateNewObject(bool busy) { var result = CreateFunc(); var objectID = _objectIDCounter += 1; var poolID = PoolID; //分配operation result.PoolObjectOperation = new PoolObjectOperation(objectID, poolID); Map[result.PoolObjectOperation.ObjectID] = result; if (!busy) { IdleObjects.Push(result); IdleIDs.Add(result.PoolObjectOperation.ObjectID); } result.OnPoolObjectCreate(); //池对象不销毁 if (IsNeverDestroyInLoad) { var component = result as Component; if (component != null) { DontDestroyOnLoad(component.gameObject); } } return result; } private void AddToIdle(IPoolObject poolObject) { var id = poolObject.PoolObjectOperation.ObjectID; IdleObjects.Push(poolObject); IdleIDs.Add(id); } private IPoolObject RemoveFromIdle() { var poolObject = IdleObjects.Pop(); IdleIDs.Remove(poolObject.PoolObjectOperation.ObjectID); return poolObject; } public IPoolObject GetPoolObject() { IPoolObject result = null; if (IdleObjects.Count > 0) { result = RemoveFromIdle(); } result ??= CreateNewObject(true); result.OnPoolObjectWakeUp(); return result; } public T GetPoolObjectAs() where T : IPoolObject { return (T)GetPoolObject(); } public void Preload(int count) { //预加载池对象 var need = count - IdleObjects.Count; if (need > 0) { for (int i = 0; i < need; i++) { CreateNewObject(false); } } } public void ReleaseIdlesObjects() { IdleIDs.Clear(); while (IdleObjects.Count > 0) { var element = IdleObjects.Pop(); if (element != null) { Map.Remove(element.PoolObjectOperation.ObjectID); var component = element as Component; if (component != null) { Destroy(component.gameObject); } } } } public bool IsCreateFromThisPool(IPoolObject poolObject) { return poolObject != null && poolObject.PoolObjectOperation.PoolID == PoolID; } public bool ContainsObject(ulong objectID) { return Map.ContainsKey(objectID); } /// /// 获取空闲ID /// public List GetIdleIDs() { return IdleIDs.ToList(); } /// /// 获取空闲数量 /// public int GetIdleCount() => IdleIDs.Count; //回收对象 internal void Internal_RecycleObject(IPoolObject poolObject) { if (poolObject == null) { #if UNITY_EDITOR Debug.Log($" 警告! 实例已被销毁,无法回收!"); #endif return; } var objectID = poolObject.PoolObjectOperation.ObjectID; if (IdleIDs.Contains(objectID)) { #if UNITY_EDITOR Debug.Log( $" 警告! {poolObject} ObjectID:{objectID} 已被回收,无法再重复回收"); #endif return; } poolObject.OnPoolObjectBeforeRecycle(); //回收前 AddToIdle(poolObject); poolObject.OnPoolObjectAfterRecycle(); //回收后 } //回收对象 internal void Internal_RecycleObject(ulong objectID) { if (Map.TryGetValue(objectID, out var match)) { //如果实例已为空 if (match == null) { Map.Remove(objectID); } Internal_RecycleObject(match); } else { throw new Exception($"回收失败,池对象:ObjectID:{objectID} 不属于池{this}"); } } protected virtual void OnDestroy() { //断开所有引用 CreateFunc = null; Map.Clear(); IdleObjects.Clear(); IdleIDs.Clear(); Map = null; IdleObjects = null; IdleIDs = null; //从管理器中移除池 PoolManager.RemovePool(PoolID); } } }