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);
}
}
}