2025-11-20 16:17:10 +08:00
|
|
|
|
using Convention.Experimental.PublicType;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Linq;
|
2025-11-14 17:13:10 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Convention.Experimental.Modules
|
|
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
public class GameObjectPoolManager : GameModule
|
2025-11-14 17:13:10 +08:00
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <para><3E>̳иýӿڵ<D3BF>Component<6E><74><EFBFBD>ڻ<EFBFBD><DABB>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><see cref="Release"/></para>
|
|
|
|
|
|
/// <para><b><see cref="Release"/><3E>н<EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD><see cref="Unspawn(GameObject)"/></b></para>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public interface IPoolPawn
|
2025-11-14 17:13:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
void Release();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 16:17:10 +08:00
|
|
|
|
private readonly Dictionary<GameObject, Stack<GameObject>> GameObjectPools = new();
|
|
|
|
|
|
private readonly Dictionary<GameObject, GameObject> LeaveGameObjectPoolObjects = new();
|
|
|
|
|
|
private bool GameObjectPoolStatus = true;
|
2025-11-14 17:13:10 +08:00
|
|
|
|
|
2025-11-20 16:17:10 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="prefab"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public bool Contains(GameObject prefab)
|
|
|
|
|
|
{
|
|
|
|
|
|
return GameObjectPools.ContainsKey(prefab);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƕ<EFBFBD><EFBFBD><D7B5><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <exception cref="GameException"></exception>
|
|
|
|
|
|
private void EnsureSafeStatus()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (GameObjectPoolStatus == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameException("GameObjectPool is busy now.");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="prefab"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-11-14 17:13:10 +08:00
|
|
|
|
public GameObject Spawn(GameObject prefab)
|
|
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
EnsureSafeStatus();
|
|
|
|
|
|
lock (GameObjectPools)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!GameObjectPools.ContainsKey(prefab))
|
|
|
|
|
|
{
|
|
|
|
|
|
GameObjectPools[prefab] = new();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var pool = GameObjectPools[prefab];
|
|
|
|
|
|
GameObject instance;
|
|
|
|
|
|
if (pool.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
instance = pool.Pop();
|
|
|
|
|
|
instance.SetActive(true);
|
|
|
|
|
|
instance.transform.SetParent(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
instance = GameObject.Instantiate(prefab);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
lock (LeaveGameObjectPoolObjects)
|
|
|
|
|
|
{
|
|
|
|
|
|
LeaveGameObjectPoolObjects[instance] = prefab;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="instance"></param>
|
|
|
|
|
|
/// <exception cref="PublicType.GameException"></exception>
|
|
|
|
|
|
public void Unspawn(GameObject instance)
|
|
|
|
|
|
{
|
|
|
|
|
|
EnsureSafeStatus();
|
|
|
|
|
|
lock (LeaveGameObjectPoolObjects)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (LeaveGameObjectPoolObjects.TryGetValue(instance, out var prefab))
|
|
|
|
|
|
{
|
|
|
|
|
|
var releaser = instance.GetComponents<IPoolPawn>();
|
|
|
|
|
|
GameObjectPoolStatus = false;
|
|
|
|
|
|
foreach (var r in releaser)
|
|
|
|
|
|
{
|
|
|
|
|
|
r.Release();
|
|
|
|
|
|
}
|
|
|
|
|
|
GameObjectPoolStatus = true;
|
|
|
|
|
|
instance.SetActive(false);
|
|
|
|
|
|
instance.transform.SetParent(ConventionUtility.Singleton.transform);
|
|
|
|
|
|
lock (GameObjectPools)
|
|
|
|
|
|
{
|
|
|
|
|
|
GameObjectPools[prefab].Push(instance);
|
|
|
|
|
|
LeaveGameObjectPoolObjects.Remove(instance);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new PublicType.GameException("This object does not belong to any pool.");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Clear(GameObject prefab)
|
|
|
|
|
|
{
|
|
|
|
|
|
EnsureSafeStatus();
|
|
|
|
|
|
lock (GameObjectPools)
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (LeaveGameObjectPoolObjects)
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD>ٳ<EFBFBD><D9B3>ж<EFBFBD><D0B6><EFBFBD>
|
|
|
|
|
|
if (GameObjectPools.TryGetValue(prefab, out var pool))
|
|
|
|
|
|
{
|
|
|
|
|
|
while (pool.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var instance = pool.Pop();
|
|
|
|
|
|
GameObject.Destroy(instance);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new PublicType.GameException("This pool does not exist.");
|
|
|
|
|
|
}
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>δ<EFBFBD><CEB4><EFBFBD>ն<EFBFBD><D5B6><EFBFBD>
|
|
|
|
|
|
var unbackInstances = from item in LeaveGameObjectPoolObjects
|
|
|
|
|
|
where item.Value == prefab
|
|
|
|
|
|
select item.Key;
|
|
|
|
|
|
foreach (var instance in unbackInstances)
|
|
|
|
|
|
{
|
|
|
|
|
|
LeaveGameObjectPoolObjects.Remove(instance);
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var instance in unbackInstances)
|
|
|
|
|
|
{
|
|
|
|
|
|
GameObject.Destroy(instance);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class ObjectPoolManager
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <para><3E>̳иýӿڵ<D3BF>Component<6E><74><EFBFBD>ڻ<EFBFBD><DABB>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><see cref="Release"/></para>
|
|
|
|
|
|
/// <para><b><see cref="Release"/><3E>н<EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD><see cref="Reclaim(object)"/></b></para>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public interface IPoolPawn
|
|
|
|
|
|
{
|
|
|
|
|
|
void Release();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private readonly Dictionary<Type, object> ObjectPools = new();
|
|
|
|
|
|
private readonly Dictionary<object, Type> LeaveObjectPoolObjects = new();
|
|
|
|
|
|
|
|
|
|
|
|
private bool GameObjectPoolStatus = true;
|
|
|
|
|
|
private void EnsureSafeStatus()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (GameObjectPoolStatus == false)
|
2025-11-14 17:13:10 +08:00
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
throw new GameException("ObjectPool is busy now.");
|
2025-11-14 17:13:10 +08:00
|
|
|
|
}
|
2025-11-20 16:17:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool Contains(Type type)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ObjectPools.ContainsKey(type);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool Contains<T>() where T : class, new()
|
|
|
|
|
|
{
|
|
|
|
|
|
return ObjectPools.ContainsKey(typeof(T));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><F3B5BDB6><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="type"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
|
|
|
|
|
/// <param name="value">ʵ<><CAB5></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="GameException"></exception>
|
|
|
|
|
|
public object Insert(Type type, object value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(LeaveObjectPoolObjects.ContainsKey(value))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new PublicType.GameException("This object is already registered in pool");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!ObjectPools.ContainsKey(type))
|
|
|
|
|
|
{
|
|
|
|
|
|
ObjectPools[type] = Utility.CreateStack(type);
|
|
|
|
|
|
}
|
|
|
|
|
|
var pool = ObjectPools[type];
|
|
|
|
|
|
var methodInfo = pool.GetType().GetMethod("Push");
|
|
|
|
|
|
methodInfo.Invoke(pool, new object[] { value });
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F3B2A2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></typeparam>
|
|
|
|
|
|
/// <param name="value">ʵ<><CAB5></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
/// <exception cref="PublicType.GameException"></exception>
|
|
|
|
|
|
public T Insert<T>(T value) where T : class
|
|
|
|
|
|
{
|
|
|
|
|
|
if(LeaveObjectPoolObjects.ContainsKey(value))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new PublicType.GameException("This object is already registered in pool");
|
|
|
|
|
|
}
|
|
|
|
|
|
var type = typeof(T);
|
|
|
|
|
|
if (!ObjectPools.ContainsKey(type))
|
|
|
|
|
|
{
|
|
|
|
|
|
ObjectPools[type] = new Stack<T>();
|
|
|
|
|
|
}
|
|
|
|
|
|
var pool = (Stack<T>)ObjectPools[type];
|
|
|
|
|
|
pool.Push(value);
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F3B2A2B7><EFBFBD>ʵ<EFBFBD><CAB5>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="type"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public object Summon(Type type)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!ObjectPools.ContainsKey(type))
|
|
|
|
|
|
{
|
|
|
|
|
|
ObjectPools[type] = Utility.CreateStack(type);
|
|
|
|
|
|
}
|
|
|
|
|
|
var pool = ObjectPools[type];
|
|
|
|
|
|
var methodInfo = pool.GetType().GetMethod("Pop");
|
|
|
|
|
|
object instance;
|
|
|
|
|
|
var countProperty = pool.GetType().GetProperty("Count");
|
|
|
|
|
|
var count = (int)countProperty.GetValue(pool);
|
|
|
|
|
|
if (count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
instance = methodInfo.Invoke(pool, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
instance = Activator.CreateInstance(type);
|
|
|
|
|
|
}
|
|
|
|
|
|
LeaveObjectPoolObjects[instance] = type;
|
|
|
|
|
|
return instance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><F3B2A2B7><EFBFBD>ʵ<EFBFBD><CAB5>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></typeparam>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public T Summon<T>() where T : class, new()
|
|
|
|
|
|
{
|
|
|
|
|
|
var type = typeof(T);
|
|
|
|
|
|
if (!ObjectPools.ContainsKey(type))
|
|
|
|
|
|
{
|
|
|
|
|
|
ObjectPools[type] = new Stack<T>();
|
|
|
|
|
|
}
|
|
|
|
|
|
var pool = (Stack<T>)ObjectPools[type];
|
|
|
|
|
|
T instance;
|
2025-11-14 17:13:10 +08:00
|
|
|
|
if (pool.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
instance = pool.Pop();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
instance = new T();
|
2025-11-14 17:13:10 +08:00
|
|
|
|
}
|
2025-11-20 16:17:10 +08:00
|
|
|
|
LeaveObjectPoolObjects[instance] = type;
|
2025-11-14 17:13:10 +08:00
|
|
|
|
return instance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 16:17:10 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>ն<EFBFBD><D5B6><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="instance">ʵ<><CAB5></param>
|
|
|
|
|
|
/// <exception cref="PublicType.GameException"></exception>
|
|
|
|
|
|
public void Reclaim(object instance)
|
2025-11-14 17:13:10 +08:00
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
if (LeaveObjectPoolObjects.TryGetValue(instance, out var objType))
|
2025-11-14 17:13:10 +08:00
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
var pool = ObjectPools[objType];
|
|
|
|
|
|
var methodInfo = pool.GetType().GetMethod("Push");
|
|
|
|
|
|
if(instance is IPoolPawn pawn)
|
2025-11-14 17:13:10 +08:00
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
pawn.Release();
|
2025-11-14 17:13:10 +08:00
|
|
|
|
}
|
2025-11-20 16:17:10 +08:00
|
|
|
|
methodInfo.Invoke(pool, new object[] { instance });
|
|
|
|
|
|
LeaveObjectPoolObjects.Remove(instance);
|
2025-11-14 17:13:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
throw new GameException("This object does not belong to any pool.");
|
2025-11-14 17:13:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 16:17:10 +08:00
|
|
|
|
public void Clear(Type type)
|
2025-11-14 17:13:10 +08:00
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
if (ObjectPools.TryGetValue(type, out var pool))
|
2025-11-14 17:13:10 +08:00
|
|
|
|
{
|
2025-11-20 16:17:10 +08:00
|
|
|
|
var clearMethod = pool.GetType().GetMethod("Clear");
|
|
|
|
|
|
clearMethod.Invoke(pool, null);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new PublicType.GameException("This pool does not exist.");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Clear<T>() where T : class, new()
|
|
|
|
|
|
{
|
|
|
|
|
|
var type = typeof(T);
|
|
|
|
|
|
if (ObjectPools.TryGetValue(type, out var pool))
|
|
|
|
|
|
{
|
|
|
|
|
|
var clearMethod = pool.GetType().GetMethod("Clear");
|
|
|
|
|
|
clearMethod.Invoke(pool, null);
|
2025-11-14 17:13:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new PublicType.GameException("This pool does not exist.");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|