26 changed files with 2471 additions and 75 deletions
@ -0,0 +1,106 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using UnityEditor; |
||||||
|
using UnityEngine; |
||||||
|
|
||||||
|
namespace Tools.EasyPoolKit.Editor |
||||||
|
{ |
||||||
|
[CustomEditor(typeof(RecyclableGOPoolKit))] |
||||||
|
public class RecyclableGOPoolKitInspector : UnityEditor.Editor |
||||||
|
{ |
||||||
|
private readonly HashSet<string> _poolIdsSet = new HashSet<string>(); |
||||||
|
|
||||||
|
public override void OnInspectorGUI() |
||||||
|
{ |
||||||
|
if (!EditorApplication.isPlaying) |
||||||
|
{ |
||||||
|
EditorGUILayout.HelpBox("Available only on runtime.", MessageType.Info); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var poolMgr = target as RecyclableGOPoolKit; |
||||||
|
|
||||||
|
if (poolMgr) |
||||||
|
{ |
||||||
|
EditorGUILayout.LabelField("RecyclableGOPoolManager"); |
||||||
|
|
||||||
|
var poolsInfo = poolMgr.GetPoolsInfo(); |
||||||
|
|
||||||
|
EditorGUILayout.LabelField("GameObject Pool Count", poolsInfo.Count.ToString()); |
||||||
|
|
||||||
|
for (int i = 0; i < poolsInfo.Count; i++) |
||||||
|
{ |
||||||
|
var poolInfo = poolsInfo[i]; |
||||||
|
DrawGameObjectPool(poolInfo); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Repaint(); |
||||||
|
} |
||||||
|
|
||||||
|
private void DrawGameObjectPool(RecyclablePoolInfo poolInfo) |
||||||
|
{ |
||||||
|
var ifLastOpened = _poolIdsSet.Contains(poolInfo.PoolId); |
||||||
|
var ifCurOpened = EditorGUILayout.Foldout(ifLastOpened, poolInfo.PoolId); |
||||||
|
|
||||||
|
if (ifCurOpened != ifLastOpened) |
||||||
|
{ |
||||||
|
if (ifCurOpened) |
||||||
|
{ |
||||||
|
_poolIdsSet.Add(poolInfo.PoolId); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
_poolIdsSet.Remove(poolInfo.PoolId); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (ifCurOpened) |
||||||
|
{ |
||||||
|
EditorGUILayout.BeginVertical("box"); |
||||||
|
{ |
||||||
|
EditorGUILayout.LabelField("PoolId", poolInfo.PoolId); |
||||||
|
EditorGUILayout.LabelField("ReferenceType", poolInfo.ReferenceType.ToString()); |
||||||
|
EditorGUILayout.LabelField("InitCreateCount", poolInfo.InitCreateCount.HasValue ? poolInfo.InitCreateCount.Value.ToString() : "-"); |
||||||
|
EditorGUILayout.LabelField("ReachMaxLimitType", poolInfo.ReachMaxLimitType.ToString()); |
||||||
|
if (poolInfo.ReachMaxLimitType != PoolReachMaxLimitType.Default) |
||||||
|
{ |
||||||
|
EditorGUILayout.LabelField("MaxSpawnCount", poolInfo.MaxSpawnCount.HasValue ? poolInfo.MaxSpawnCount.Value.ToString() : "-"); |
||||||
|
} |
||||||
|
EditorGUILayout.LabelField("DespawnDestroyType", poolInfo.DespawnDestroyType.ToString()); |
||||||
|
if (poolInfo.DespawnDestroyType == PoolDespawnDestroyType.DestroyToLimit) |
||||||
|
{ |
||||||
|
EditorGUILayout.LabelField("MaxDespawnCount", poolInfo.MaxDespawnCount.HasValue ? poolInfo.MaxDespawnCount.Value.ToString() : "-"); |
||||||
|
} |
||||||
|
|
||||||
|
EditorGUILayout.LabelField("ClearType", poolInfo.ClearType.ToString()); |
||||||
|
EditorGUILayout.LabelField("AutoClearTime", poolInfo.AutoClearTime.ToString()); |
||||||
|
EditorGUILayout.LabelField("IfIgnoreTimeScale", poolInfo.IsIgnoreTimeScale.ToString()); |
||||||
|
EditorGUILayout.LabelField("CachedObjectCount", poolInfo.CachedObjectCount.ToString()); |
||||||
|
EditorGUILayout.LabelField("UsedObjectCount", poolInfo.UsedObjectCount.ToString()); |
||||||
|
EditorGUILayout.LabelField("TotalObjectCount", poolInfo.TotalObjectCount.ToString()); |
||||||
|
|
||||||
|
if (GUILayout.Button("ClearUnusedObjects(Safe)")) |
||||||
|
{ |
||||||
|
if (poolInfo.ExtraInfo is RecyclableGameObjectPool pool) |
||||||
|
{ |
||||||
|
pool.ClearUnusedObjects(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (GUILayout.Button("ClearPool(Unsafe)")) |
||||||
|
{ |
||||||
|
if (poolInfo.ExtraInfo is RecyclableGameObjectPool pool) |
||||||
|
{ |
||||||
|
pool.ClearAll(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//TODO Draw all Objects |
||||||
|
} |
||||||
|
EditorGUILayout.EndVertical(); |
||||||
|
|
||||||
|
EditorGUILayout.Separator(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 4f91df83af2a4b1783596dc115062a57 |
||||||
|
timeCreated: 1735968672 |
@ -0,0 +1,3 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 1b4c6592766748e9850e7f96f3242d3b |
||||||
|
timeCreated: 1735963479 |
@ -0,0 +1,51 @@ |
|||||||
|
using System; |
||||||
|
using NUnit.Framework; |
||||||
|
using UnityEngine; |
||||||
|
|
||||||
|
namespace Tools.EasyPoolKit |
||||||
|
{ |
||||||
|
public class RecyclableGOPoolKit : RecyclableGOPoolManagerBase |
||||||
|
{ |
||||||
|
public static RecyclableGOPoolKit Instance |
||||||
|
{ |
||||||
|
get |
||||||
|
{ |
||||||
|
if (_instance == null) |
||||||
|
{ |
||||||
|
var poolRoot = new GameObject("RecyclableGOPoolKit"); |
||||||
|
var cachedRoot = new GameObject("CachedRoot"); |
||||||
|
cachedRoot.transform.SetParent(poolRoot.transform, false); |
||||||
|
cachedRoot.gameObject.SetActive(false); |
||||||
|
_instance = poolRoot.AddComponent<RecyclableGOPoolKit>(); |
||||||
|
_instance.CachedRoot = cachedRoot.transform; |
||||||
|
DontDestroyOnLoad(_instance.gameObject); |
||||||
|
} |
||||||
|
return _instance; |
||||||
|
} |
||||||
|
} |
||||||
|
private static RecyclableGOPoolKit _instance; |
||||||
|
|
||||||
|
private void Awake() |
||||||
|
{ |
||||||
|
if (_instance != null) |
||||||
|
{ |
||||||
|
Debug.LogError("EasyPoolKit == Don't attach RecyclableGOPoolManager on any object, use SimpleGOPoolManager.Instance instead!"); |
||||||
|
Destroy(gameObject); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override RecyclablePoolConfig GetDefaultPrefabPoolConfig(string poolPrefix, GameObject prefabAsset, Func<RecyclableMonoBehaviour> spawnFunc) |
||||||
|
{ |
||||||
|
Assert.IsNotNull(prefabAsset); |
||||||
|
var poolConfig = new RecyclablePoolConfig() |
||||||
|
{ |
||||||
|
ObjectType = RecycleObjectType.RecyclableGameObject, |
||||||
|
ReferenceType = typeof(GameObject), |
||||||
|
PoolId = $"RecyclableGOPool_{poolPrefix ?? string.Empty}_{prefabAsset.GetInstanceID()}", |
||||||
|
SpawnFunc = spawnFunc, |
||||||
|
}; |
||||||
|
|
||||||
|
return poolConfig; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 8cff55e0843e4bd0875e328d0b7216d5 |
||||||
|
timeCreated: 1735965986 |
@ -0,0 +1,230 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using UnityEngine; |
||||||
|
using UnityEngine.Assertions; |
||||||
|
|
||||||
|
namespace Tools.EasyPoolKit |
||||||
|
{ |
||||||
|
public abstract class RecyclableGOPoolManagerBase : MonoBehaviour |
||||||
|
{ |
||||||
|
public string PoolPrefix = string.Empty; |
||||||
|
|
||||||
|
/// 缓存根节点 |
||||||
|
protected Transform CachedRoot; |
||||||
|
|
||||||
|
/// key: 预制体的HashID, value: 对应的预制体 |
||||||
|
private Dictionary<int, GameObject> _prefabTemplates = new Dictionary<int, GameObject>(); |
||||||
|
|
||||||
|
/// key: 预制体的HashID, value: 对应的对象池 |
||||||
|
private Dictionary<int, RecyclableGameObjectPool> _gameObjPools = new Dictionary<int, RecyclableGameObjectPool>(); |
||||||
|
|
||||||
|
/// key: 激活的物体实例的HashID, value: 对应的预制体的HashID |
||||||
|
private List<RecyclablePoolInfo> _poolInfoList = new List<RecyclablePoolInfo>(); |
||||||
|
public List<RecyclablePoolInfo> GetPoolsInfo() => _poolInfoList; |
||||||
|
|
||||||
|
private bool _ifAppQuit = false; |
||||||
|
|
||||||
|
/// 检测是否已有对应的对象池 |
||||||
|
public bool IfPoolValid(int prefabHash) => _prefabTemplates.ContainsKey(prefabHash) && _gameObjPools.ContainsKey(prefabHash); |
||||||
|
|
||||||
|
private void Update() |
||||||
|
{ |
||||||
|
foreach (var poolPair in _gameObjPools) |
||||||
|
{ |
||||||
|
var pool = poolPair.Value; |
||||||
|
var deltaTime = pool.IsIgnoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime; |
||||||
|
pool.OnPoolUpdate(deltaTime); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void OnApplicationQuit() |
||||||
|
{ |
||||||
|
_ifAppQuit = true; |
||||||
|
} |
||||||
|
|
||||||
|
private void OnDestroy() |
||||||
|
{ |
||||||
|
if (!_ifAppQuit) |
||||||
|
{ |
||||||
|
ClearAllPools(true); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public RecyclableGameObjectPool RegisterPrefab(GameObject prefabAsset, RecyclablePoolConfig config = null) |
||||||
|
{ |
||||||
|
Assert.IsNotNull(prefabAsset); |
||||||
|
|
||||||
|
var prefabHash = prefabAsset.GetInstanceID(); |
||||||
|
|
||||||
|
#if EASY_POOL_DEBUG |
||||||
|
if (_gameObjPools.ContainsKey(prefabHash) || _prefabTemplates.ContainsKey(prefabHash)) |
||||||
|
{ |
||||||
|
Debug.LogError($"EasyPoolKit == RegisterPrefab {prefabAsset.name} but already registered"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
if (config == null) |
||||||
|
{ |
||||||
|
config = GetDefaultPrefabPoolConfig(PoolPrefix, prefabAsset, null); |
||||||
|
} |
||||||
|
|
||||||
|
if (config.SpawnFunc == null) |
||||||
|
{ |
||||||
|
config.SpawnFunc = () => DefaultCreateObjectFunc(prefabHash); |
||||||
|
} |
||||||
|
|
||||||
|
if (config.ExtraArgs == null || config.ExtraArgs.Length == 0) |
||||||
|
{ |
||||||
|
config.ExtraArgs = new object[] { CachedRoot }; |
||||||
|
} |
||||||
|
|
||||||
|
_prefabTemplates[prefabHash] = prefabAsset; |
||||||
|
var newPool = new RecyclableGameObjectPool(config); |
||||||
|
_gameObjPools[prefabHash] = newPool; |
||||||
|
_poolInfoList.Add(newPool.GetPoolInfoReadOnly()); |
||||||
|
|
||||||
|
return newPool; |
||||||
|
} |
||||||
|
|
||||||
|
public bool UnRegisterPrefab(int prefabHash) |
||||||
|
{ |
||||||
|
_prefabTemplates.Remove(prefabHash); |
||||||
|
|
||||||
|
if (_gameObjPools.TryGetValue(prefabHash, out var pool)) |
||||||
|
{ |
||||||
|
pool.ClearAll(); |
||||||
|
_poolInfoList.Remove(pool.GetPoolInfoReadOnly()); |
||||||
|
_gameObjPools.Remove(prefabHash); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public RecyclableMonoBehaviour SimpleSpawn(GameObject prefabTemplate) |
||||||
|
{ |
||||||
|
if (prefabTemplate == null) |
||||||
|
{ |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
var prefabHash = prefabTemplate.GetInstanceID(); |
||||||
|
|
||||||
|
if (!_gameObjPools.TryGetValue(prefabHash, out var pool)) |
||||||
|
{ |
||||||
|
pool = RegisterPrefab(prefabTemplate); |
||||||
|
} |
||||||
|
|
||||||
|
return pool.SpawnObject(); |
||||||
|
} |
||||||
|
|
||||||
|
public T SimpleSpawn<T>(GameObject prefabTemplate) where T :RecyclableMonoBehaviour |
||||||
|
{ |
||||||
|
return SimpleSpawn(prefabTemplate) as T; |
||||||
|
} |
||||||
|
|
||||||
|
public bool TrySpawn(int prefabHash, out RecyclableMonoBehaviour recyclableObj) |
||||||
|
{ |
||||||
|
recyclableObj = null; |
||||||
|
if (_gameObjPools.TryGetValue(prefabHash, out var pool)) |
||||||
|
{ |
||||||
|
recyclableObj = pool.SpawnObject(); |
||||||
|
} |
||||||
|
|
||||||
|
return recyclableObj != null; |
||||||
|
} |
||||||
|
|
||||||
|
public bool TrySpawn<T>(int prefabHash, out T recyclableObj) where T :RecyclableMonoBehaviour |
||||||
|
{ |
||||||
|
recyclableObj = null; |
||||||
|
if (TrySpawn(prefabHash, out var newObj)) |
||||||
|
{ |
||||||
|
recyclableObj = newObj as T; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public bool Despawn(RecyclableMonoBehaviour recyclableObj) |
||||||
|
{ |
||||||
|
Assert.IsNotNull(recyclableObj); |
||||||
|
return recyclableObj.DespawnSelf(); |
||||||
|
} |
||||||
|
|
||||||
|
public bool ClearPoolByAssetHash(int prefabHash, bool onlyClearUnused = false) |
||||||
|
{ |
||||||
|
if (_gameObjPools.TryGetValue(prefabHash, out var pool)) |
||||||
|
{ |
||||||
|
if (onlyClearUnused) |
||||||
|
{ |
||||||
|
pool.ClearUnusedObjects(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
pool.ClearAll(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public void ClearAllUnusedObjects() |
||||||
|
{ |
||||||
|
foreach (var poolPair in _gameObjPools) |
||||||
|
{ |
||||||
|
poolPair.Value.ClearUnusedObjects(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void ClearAllPools(bool ifDestroy) |
||||||
|
{ |
||||||
|
foreach (var pool in _gameObjPools) |
||||||
|
{ |
||||||
|
pool.Value.ClearAll(); |
||||||
|
} |
||||||
|
|
||||||
|
if (ifDestroy) |
||||||
|
{ |
||||||
|
if (CachedRoot) |
||||||
|
{ |
||||||
|
for (int i = CachedRoot.childCount - 1; i >= 0; i--) |
||||||
|
{ |
||||||
|
var child = CachedRoot.GetChild(i).gameObject; |
||||||
|
Destroy(child); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_prefabTemplates.Clear(); |
||||||
|
_poolInfoList.Clear(); |
||||||
|
_gameObjPools.Clear(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private RecyclableMonoBehaviour DefaultCreateObjectFunc(int prefabHash) |
||||||
|
{ |
||||||
|
if (_prefabTemplates.TryGetValue(prefabHash, out var prefabAsset)) |
||||||
|
{ |
||||||
|
if (prefabAsset != null) |
||||||
|
{ |
||||||
|
var gameObj = Instantiate(prefabAsset); |
||||||
|
var recyclableObj = gameObj.GetOrCreateRecyclableMono(); |
||||||
|
recyclableObj.PrefabHash = prefabHash; |
||||||
|
return recyclableObj; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Debug.LogError($"EasyPoolKit == Cannot create object: {prefabHash}"); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public abstract RecyclablePoolConfig GetDefaultPrefabPoolConfig(string poolPrefix, GameObject prefabAsset, |
||||||
|
Func<RecyclableMonoBehaviour> spawnFunc); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 8cde1003a7854925ac58c691ed66bdf9 |
||||||
|
timeCreated: 1735966230 |
@ -0,0 +1,49 @@ |
|||||||
|
using UnityEngine; |
||||||
|
|
||||||
|
namespace Tools.EasyPoolKit |
||||||
|
{ |
||||||
|
public class RecyclableGameObjectPool : RecyclablePoolBase<RecyclableMonoBehaviour> |
||||||
|
{ |
||||||
|
private Transform _cachedRoot; |
||||||
|
|
||||||
|
public RecyclableGameObjectPool(RecyclablePoolConfig config) : base(config) { } |
||||||
|
|
||||||
|
protected override void OnInitByParams(object[] args) |
||||||
|
{ |
||||||
|
var extraArgs = args; |
||||||
|
|
||||||
|
if (extraArgs != null && extraArgs.Length > 0 && extraArgs[0] is Transform root) |
||||||
|
{ |
||||||
|
_cachedRoot = root; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
Debug.LogError("EasyPoolKit == Create RecyclableMonoPool should input the root Transform in extraArgs[0]"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnObjectInit(RecyclableMonoBehaviour usedObj) |
||||||
|
{ |
||||||
|
usedObj.Pool = this; |
||||||
|
usedObj.PoolId = PoolId; |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnObjectEnqueue(RecyclableMonoBehaviour usedObj) |
||||||
|
{ |
||||||
|
usedObj.transform.SetParent(_cachedRoot, true); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnObjectDequeue(RecyclableMonoBehaviour usedObj) |
||||||
|
{ |
||||||
|
usedObj.transform.SetParent(null, true); |
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnObjectDestoryInit(RecyclableMonoBehaviour usedObj) |
||||||
|
{ |
||||||
|
if (usedObj) |
||||||
|
{ |
||||||
|
Object.Destroy(usedObj.gameObject); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 6ab2cfde92374470825bf4ff3b0ac5a3 |
||||||
|
timeCreated: 1735964092 |
@ -0,0 +1,88 @@ |
|||||||
|
using UnityEngine; |
||||||
|
using UnityEngine.Assertions; |
||||||
|
|
||||||
|
namespace Tools.EasyPoolKit |
||||||
|
{ |
||||||
|
public class RecyclableMonoBehaviour : MonoBehaviour, IRecyclable |
||||||
|
{ |
||||||
|
public bool EnableMessage = false; |
||||||
|
|
||||||
|
public RecyclableGameObjectPool Pool { get; set; } |
||||||
|
|
||||||
|
public static readonly string MessageOnInit = "OnObjectInit"; |
||||||
|
public static readonly string MessageOnDeInit = "OnObjectDeInit"; |
||||||
|
public static readonly string MessageOnSpawn = "OnObjectSpawn"; |
||||||
|
public static readonly string MessageOnDespawn = "OnObjectDespawn"; |
||||||
|
|
||||||
|
public RecycleObjectType ObjectType => RecycleObjectType.RecyclableGameObject; |
||||||
|
public string PoolId { get; set; } |
||||||
|
public int ObjectId { get; set; } |
||||||
|
public string Name { get => gameObject.name; set => gameObject.name = value; } |
||||||
|
public float UsedTime { get; set; } |
||||||
|
|
||||||
|
public int PrefabHash { get; set; } |
||||||
|
|
||||||
|
public virtual void OnObjectInit() |
||||||
|
{ |
||||||
|
if (EnableMessage) |
||||||
|
{ |
||||||
|
SendMessage(MessageOnInit, SendMessageOptions.DontRequireReceiver); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void OnObjectDestroyInit() |
||||||
|
{ |
||||||
|
if (EnableMessage) |
||||||
|
{ |
||||||
|
SendMessage(MessageOnDeInit, SendMessageOptions.DontRequireReceiver); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void OnObjectSpawn() |
||||||
|
{ |
||||||
|
if (EnableMessage) |
||||||
|
{ |
||||||
|
SendMessage(MessageOnSpawn, SendMessageOptions.DontRequireReceiver); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void OnObjectDespawn() |
||||||
|
{ |
||||||
|
UsedTime = 0; |
||||||
|
PrefabHash = 0; |
||||||
|
|
||||||
|
if (EnableMessage) |
||||||
|
{ |
||||||
|
SendMessage(MessageOnDespawn, SendMessageOptions.DontRequireReceiver); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void OnObjectUpdate(float deltaTime) |
||||||
|
{ |
||||||
|
UsedTime += deltaTime; |
||||||
|
} |
||||||
|
|
||||||
|
public bool DespawnSelf() |
||||||
|
{ |
||||||
|
return Pool.DespawnObject(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static class RecyclableMonoBehaviourExt |
||||||
|
{ |
||||||
|
public static RecyclableMonoBehaviour GetOrCreateRecyclableMono(this GameObject gameObj, |
||||||
|
bool enableMessage = false) |
||||||
|
{ |
||||||
|
Assert.IsNotNull(gameObj); |
||||||
|
var recyclableMono = gameObj.GetComponent<RecyclableMonoBehaviour>(); |
||||||
|
if (recyclableMono) |
||||||
|
{ |
||||||
|
return recyclableMono; |
||||||
|
} |
||||||
|
recyclableMono = gameObj.AddComponent<RecyclableMonoBehaviour>(); |
||||||
|
recyclableMono.EnableMessage = enableMessage; |
||||||
|
return recyclableMono; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: cc3dd3e8963f45f198d01d5e6664032e |
||||||
|
timeCreated: 1735963499 |
@ -0,0 +1,387 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Tools.EasyPoolKit |
||||||
|
{ |
||||||
|
public abstract class RecyclablePoolBase<T> : IRecyclablePool<T> where T : class, IRecyclable |
||||||
|
{ |
||||||
|
protected Queue<T> CachedQueue { get; private set; } |
||||||
|
|
||||||
|
protected LinkedList<T> UsedList { get; private set; } |
||||||
|
|
||||||
|
private int _objectCounter = 0; |
||||||
|
|
||||||
|
private bool _ifInit = false; |
||||||
|
|
||||||
|
public RecycleObjectType ObjectType { get; private set;} |
||||||
|
public Type ReferenceType { get; private set;} |
||||||
|
public string PoolId { get; private set;} |
||||||
|
public int? InitCreateCount { get; private set;} |
||||||
|
public int? MaxSpawnCount { get; private set;} |
||||||
|
public int? MaxDespawnCount { get; private set;} |
||||||
|
public float? AutoClearTime { get; private set;} |
||||||
|
public Func<object> SpawnFunc { get; set; } |
||||||
|
public PoolReachMaxLimitType ReachMaxLimitType { get; private set;} |
||||||
|
public PoolDespawnDestroyType DespawnDestroyType { get; private set;} |
||||||
|
public PoolClearType ClearType { get; private set;} |
||||||
|
public bool IsIgnoreTimeScale { get; private set;} |
||||||
|
|
||||||
|
public int GetCachedObjectCount() => CachedQueue.Count; |
||||||
|
public int GetUsedObjectCount() => UsedList.Count; |
||||||
|
public int GetTotalObjectCount() => CachedQueue.Count + UsedList.Count; |
||||||
|
|
||||||
|
protected readonly RecyclablePoolInfo PoolInfo; |
||||||
|
public RecyclablePoolInfo GetPoolInfoReadOnly() => PoolInfo; |
||||||
|
|
||||||
|
public RecyclablePoolBase(RecyclablePoolConfig config) |
||||||
|
{ |
||||||
|
PoolInfo = InitByConfig(config); |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual RecyclablePoolInfo InitByConfig(RecyclablePoolConfig config) |
||||||
|
{ |
||||||
|
if (_ifInit) |
||||||
|
{ |
||||||
|
throw new Exception("EasyEventPool == Already Init!"); |
||||||
|
} |
||||||
|
|
||||||
|
if (config == null) |
||||||
|
{ |
||||||
|
throw new Exception("EasyEventPool == config is null!"); |
||||||
|
} |
||||||
|
|
||||||
|
ObjectType = config.ObjectType; |
||||||
|
ReferenceType = config.ReferenceType; |
||||||
|
PoolId = config.PoolId; |
||||||
|
SpawnFunc = config.SpawnFunc ?? throw new Exception("EasyEventPool == config.SpawnFunc is null!"); |
||||||
|
ReachMaxLimitType = config.ReachMaxLimitType; |
||||||
|
DespawnDestroyType = config.DespawnDestroyType; |
||||||
|
ClearType = config.ClearType; |
||||||
|
InitCreateCount = config.InitCreateCount; |
||||||
|
MaxSpawnCount = config.MaxSpawnCount; |
||||||
|
MaxDespawnCount = config.MaxDespawnCount; |
||||||
|
AutoClearTime = config.AutoClearTime; |
||||||
|
IsIgnoreTimeScale = config.IsIgnoreTimeScale; |
||||||
|
|
||||||
|
var poolInfo = new RecyclablePoolInfo(config, GetCachedObjectCount, GetUsedObjectCount, GetTotalObjectCount, this); |
||||||
|
|
||||||
|
CachedQueue = MaxSpawnCount.HasValue |
||||||
|
? new Queue<T>(MaxSpawnCount.Value + 1) |
||||||
|
: new Queue<T>(); |
||||||
|
|
||||||
|
UsedList = new LinkedList<T>(); |
||||||
|
OnInitByParams(config.ExtraArgs); |
||||||
|
InitCachedPool(); |
||||||
|
_ifInit = true; |
||||||
|
|
||||||
|
#if EASY_POOL_DEBUG |
||||||
|
//Check if params are valid |
||||||
|
if (ReachMaxLimitType == PoolReachMaxLimitType.RejectNull || |
||||||
|
ReachMaxLimitType == PoolReachMaxLimitType.RecycleOldest) |
||||||
|
{ |
||||||
|
if (!(MaxSpawnCount.HasValue && MaxSpawnCount.Value > 0)) |
||||||
|
{ |
||||||
|
throw new Exception("MaxSpawnCount.Value should > 0"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (DespawnDestroyType == PoolDespawnDestroyType.DestroyToLimit) |
||||||
|
{ |
||||||
|
if (!(MaxDespawnCount.HasValue && MaxDespawnCount.Value > 0)) |
||||||
|
{ |
||||||
|
throw new Exception("MaxDespawnCount.Value should > 0"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (MaxSpawnCount.HasValue && MaxDespawnCount.HasValue) |
||||||
|
{ |
||||||
|
if (!(MaxDespawnCount.Value <= MaxSpawnCount.Value)) |
||||||
|
{ |
||||||
|
throw new Exception("MaxDespawnCount.Value should <= MaxSpawnCount.Value"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (MaxSpawnCount.HasValue && InitCreateCount.HasValue) |
||||||
|
{ |
||||||
|
if (!(InitCreateCount.Value <= MaxSpawnCount.Value)) |
||||||
|
{ |
||||||
|
throw new Exception("InitCreateCount.Value should <= MaxSpawnCount.Value"); |
||||||
|
} |
||||||
|
} |
||||||
|
#endif |
||||||
|
return poolInfo; |
||||||
|
} |
||||||
|
|
||||||
|
public T SpawnObject() |
||||||
|
{ |
||||||
|
T cachedObj = null; |
||||||
|
|
||||||
|
if (GetCachedObjectCount() > 0) |
||||||
|
{ |
||||||
|
cachedObj = CachedQueue.Dequeue(); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
bool ifReachLimit = false; |
||||||
|
|
||||||
|
if (ReachMaxLimitType != PoolReachMaxLimitType.Default && MaxSpawnCount.HasValue) |
||||||
|
{ |
||||||
|
ifReachLimit = GetTotalObjectCount() >= MaxSpawnCount.Value; |
||||||
|
} |
||||||
|
|
||||||
|
if (!ifReachLimit) |
||||||
|
{ |
||||||
|
cachedObj = CreateObject(); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
switch (ReachMaxLimitType) |
||||||
|
{ |
||||||
|
case PoolReachMaxLimitType.RecycleOldest: |
||||||
|
cachedObj = RecycleOldestObject(); |
||||||
|
break; |
||||||
|
case PoolReachMaxLimitType.Default: |
||||||
|
//Impossible |
||||||
|
case PoolReachMaxLimitType.RejectNull: |
||||||
|
default: |
||||||
|
//do nothing |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (cachedObj != null) |
||||||
|
{ |
||||||
|
OnObjectDequeue(cachedObj); |
||||||
|
cachedObj.OnObjectSpawn(); |
||||||
|
UsedList.AddLast(cachedObj); |
||||||
|
} |
||||||
|
|
||||||
|
return cachedObj; |
||||||
|
} |
||||||
|
|
||||||
|
public bool TrySpawnObject(out T newObj) |
||||||
|
{ |
||||||
|
newObj = SpawnObject(); |
||||||
|
return newObj != null; |
||||||
|
} |
||||||
|
|
||||||
|
public bool DespawnObject(T usedObj) |
||||||
|
{ |
||||||
|
if (usedObj == null) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
var usedNode = UsedList.Find(usedObj); |
||||||
|
|
||||||
|
if (usedNode == null) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool ifReachLimit = false; |
||||||
|
|
||||||
|
if (DespawnDestroyType == PoolDespawnDestroyType.DestroyToLimit) |
||||||
|
{ |
||||||
|
if (MaxDespawnCount.HasValue && GetTotalObjectCount() > MaxDespawnCount.Value) |
||||||
|
{ |
||||||
|
ifReachLimit = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
UsedList.Remove(usedNode); |
||||||
|
usedObj.OnObjectDespawn(); |
||||||
|
|
||||||
|
if (ifReachLimit) |
||||||
|
{ |
||||||
|
DestroyPoolObject(usedObj); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
CachedQueue.Enqueue(usedObj); |
||||||
|
OnObjectEnqueue(usedObj); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public void OnPoolUpdate(float deltaTime) |
||||||
|
{ |
||||||
|
if (UsedList.Count > 0) |
||||||
|
{ |
||||||
|
var beginNode = UsedList.First; |
||||||
|
float collectTime = AutoClearTime ?? -1f; |
||||||
|
|
||||||
|
while (beginNode != null) |
||||||
|
{ |
||||||
|
var currentNode = beginNode; |
||||||
|
beginNode = beginNode.Next; |
||||||
|
var usedObj = currentNode.Value; |
||||||
|
usedObj.OnObjectUpdate(deltaTime); |
||||||
|
|
||||||
|
if (collectTime > 0 && usedObj.UsedTime >= collectTime) |
||||||
|
{ |
||||||
|
DespawnObject(usedObj); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void InitCachedPool() |
||||||
|
{ |
||||||
|
if (!InitCreateCount.HasValue) |
||||||
|
{ |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var initCount = InitCreateCount.Value; |
||||||
|
|
||||||
|
for (int i = 0; i < initCount; i++) |
||||||
|
{ |
||||||
|
var cachedObj = CreateObject(); |
||||||
|
CachedQueue.Enqueue(cachedObj); |
||||||
|
OnObjectEnqueue(cachedObj); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private T CreateObject() |
||||||
|
{ |
||||||
|
_objectCounter++; |
||||||
|
|
||||||
|
if (SpawnFunc?.Invoke() is T cachedObj) |
||||||
|
{ |
||||||
|
cachedObj.PoolId = PoolId; |
||||||
|
cachedObj.ObjectId = _objectCounter; |
||||||
|
|
||||||
|
#if EASY_POOL_DEBUG |
||||||
|
cachedObj.Name = $"{PoolId}_{cachedObj.ObjectId}"; |
||||||
|
#endif |
||||||
|
OnObjectInit(cachedObj); |
||||||
|
cachedObj.OnObjectInit(); |
||||||
|
} |
||||||
|
#if EASY_POOL_DEBUG |
||||||
|
else |
||||||
|
{ |
||||||
|
throw new Exception($"EasyPoolKit == GenerateObject {PoolId} Should not be null!"); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
return cachedObj; |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual void OnInitByParams(object[] args){} |
||||||
|
protected abstract void OnObjectInit(T usedObj); |
||||||
|
protected abstract void OnObjectEnqueue(T usedObj); |
||||||
|
protected abstract void OnObjectDequeue(T usedObj); |
||||||
|
protected abstract void OnObjectDestoryInit(T usedObj); |
||||||
|
|
||||||
|
private T RecycleOldestObject() |
||||||
|
{ |
||||||
|
var firstNode = UsedList.First; |
||||||
|
UsedList.Remove(firstNode); |
||||||
|
var oldestObj = firstNode.Value; |
||||||
|
|
||||||
|
if (oldestObj != null) |
||||||
|
{ |
||||||
|
oldestObj.OnObjectDespawn(); |
||||||
|
} |
||||||
|
|
||||||
|
//As it is a free node, need not to add it to cachedQueue |
||||||
|
return oldestObj; |
||||||
|
} |
||||||
|
|
||||||
|
private void DestroyPoolObject(T poolObj) |
||||||
|
{ |
||||||
|
if (poolObj != null) |
||||||
|
{ |
||||||
|
poolObj.OnObjectDestroyInit(); |
||||||
|
OnObjectDestoryInit(poolObj); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#region Clear |
||||||
|
|
||||||
|
public void ClearUnusedObjects() |
||||||
|
{ |
||||||
|
foreach (var cachedItem in CachedQueue) |
||||||
|
{ |
||||||
|
DestroyPoolObject(cachedItem); |
||||||
|
} |
||||||
|
|
||||||
|
CachedQueue.Clear(); |
||||||
|
} |
||||||
|
|
||||||
|
public void ClearAll() |
||||||
|
{ |
||||||
|
switch (ClearType) |
||||||
|
{ |
||||||
|
case PoolClearType.Default: |
||||||
|
poolClearAll(); |
||||||
|
break; |
||||||
|
case PoolClearType.ClearToLimit: |
||||||
|
poolClearToLimit(); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
void poolClearAll() |
||||||
|
{ |
||||||
|
foreach (var cachedItem in CachedQueue) |
||||||
|
{ |
||||||
|
DestroyPoolObject(cachedItem); |
||||||
|
} |
||||||
|
|
||||||
|
CachedQueue.Clear(); |
||||||
|
|
||||||
|
while (UsedList.Count > 0) |
||||||
|
{ |
||||||
|
var firstNode = UsedList.First; |
||||||
|
var firstObj = firstNode.Value; |
||||||
|
UsedList.Remove(firstNode); |
||||||
|
DestroyPoolObject(firstObj); |
||||||
|
} |
||||||
|
|
||||||
|
UsedList.Clear(); |
||||||
|
} |
||||||
|
|
||||||
|
void poolClearToLimit() |
||||||
|
{ |
||||||
|
if (!InitCreateCount.HasValue) |
||||||
|
{ |
||||||
|
poolClearAll(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
poolClearRetain(); |
||||||
|
|
||||||
|
int removeCount = GetCachedObjectCount() - InitCreateCount.Value; |
||||||
|
|
||||||
|
while (removeCount > 0) |
||||||
|
{ |
||||||
|
removeCount--; |
||||||
|
var cachedObj = CachedQueue.Dequeue(); |
||||||
|
DestroyPoolObject(cachedObj); |
||||||
|
} |
||||||
|
|
||||||
|
// 回收正在使用的物体 |
||||||
|
void poolClearRetain() |
||||||
|
{ |
||||||
|
while (UsedList.Count > 0) |
||||||
|
{ |
||||||
|
var firstNode = UsedList.First; |
||||||
|
var firstObj = firstNode.Value; |
||||||
|
DespawnObject(firstObj); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
#region Debug |
||||||
|
public string GetDebugConfigInfo() => PoolInfo?.GetDebugConfigInfo() ?? string.Empty; |
||||||
|
public string GetDebugRunningInfo() => PoolInfo?.GetDebugRunningInfo() ?? string.Empty; |
||||||
|
#endregion |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 2f64392ce63446c280cd10dee37231e8 |
||||||
|
timeCreated: 1735964418 |
@ -0,0 +1,8 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 259a517e8654b99499c0f17a15beb06f |
||||||
|
folderAsset: yes |
||||||
|
DefaultImporter: |
||||||
|
externalObjects: {} |
||||||
|
userData: |
||||||
|
assetBundleName: |
||||||
|
assetBundleVariant: |
@ -0,0 +1,274 @@ |
|||||||
|
%YAML 1.1 |
||||||
|
%TAG !u! tag:unity3d.com,2011: |
||||||
|
--- !u!1 &212430069314405427 |
||||||
|
GameObject: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
serializedVersion: 6 |
||||||
|
m_Component: |
||||||
|
- component: {fileID: 5249829104186841453} |
||||||
|
- component: {fileID: 8202632885764616307} |
||||||
|
- component: {fileID: 7186356064517121775} |
||||||
|
m_Layer: 5 |
||||||
|
m_Name: Text (TMP) |
||||||
|
m_TagString: Untagged |
||||||
|
m_Icon: {fileID: 0} |
||||||
|
m_NavMeshLayer: 0 |
||||||
|
m_StaticEditorFlags: 0 |
||||||
|
m_IsActive: 1 |
||||||
|
--- !u!224 &5249829104186841453 |
||||||
|
RectTransform: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
m_GameObject: {fileID: 212430069314405427} |
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} |
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0} |
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1} |
||||||
|
m_ConstrainProportionsScale: 0 |
||||||
|
m_Children: [] |
||||||
|
m_Father: {fileID: 6440907175184653233} |
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} |
||||||
|
m_AnchorMin: {x: 0, y: 0} |
||||||
|
m_AnchorMax: {x: 1, y: 1} |
||||||
|
m_AnchoredPosition: {x: 0, y: 0} |
||||||
|
m_SizeDelta: {x: 0, y: 0} |
||||||
|
m_Pivot: {x: 0.5, y: 0.5} |
||||||
|
--- !u!222 &8202632885764616307 |
||||||
|
CanvasRenderer: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
m_GameObject: {fileID: 212430069314405427} |
||||||
|
m_CullTransparentMesh: 1 |
||||||
|
--- !u!114 &7186356064517121775 |
||||||
|
MonoBehaviour: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
m_GameObject: {fileID: 212430069314405427} |
||||||
|
m_Enabled: 1 |
||||||
|
m_EditorHideFlags: 0 |
||||||
|
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} |
||||||
|
m_Name: |
||||||
|
m_EditorClassIdentifier: |
||||||
|
m_Material: {fileID: 0} |
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1} |
||||||
|
m_RaycastTarget: 1 |
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} |
||||||
|
m_Maskable: 1 |
||||||
|
m_OnCullStateChanged: |
||||||
|
m_PersistentCalls: |
||||||
|
m_Calls: [] |
||||||
|
m_text: Button |
||||||
|
m_isRightToLeft: 0 |
||||||
|
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} |
||||||
|
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} |
||||||
|
m_fontSharedMaterials: [] |
||||||
|
m_fontMaterial: {fileID: 0} |
||||||
|
m_fontMaterials: [] |
||||||
|
m_fontColor32: |
||||||
|
serializedVersion: 2 |
||||||
|
rgba: 4281479730 |
||||||
|
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} |
||||||
|
m_enableVertexGradient: 0 |
||||||
|
m_colorMode: 3 |
||||||
|
m_fontColorGradient: |
||||||
|
topLeft: {r: 1, g: 1, b: 1, a: 1} |
||||||
|
topRight: {r: 1, g: 1, b: 1, a: 1} |
||||||
|
bottomLeft: {r: 1, g: 1, b: 1, a: 1} |
||||||
|
bottomRight: {r: 1, g: 1, b: 1, a: 1} |
||||||
|
m_fontColorGradientPreset: {fileID: 0} |
||||||
|
m_spriteAsset: {fileID: 0} |
||||||
|
m_tintAllSprites: 0 |
||||||
|
m_StyleSheet: {fileID: 0} |
||||||
|
m_TextStyleHashCode: -1183493901 |
||||||
|
m_overrideHtmlColors: 0 |
||||||
|
m_faceColor: |
||||||
|
serializedVersion: 2 |
||||||
|
rgba: 4294967295 |
||||||
|
m_fontSize: 24 |
||||||
|
m_fontSizeBase: 24 |
||||||
|
m_fontWeight: 400 |
||||||
|
m_enableAutoSizing: 0 |
||||||
|
m_fontSizeMin: 18 |
||||||
|
m_fontSizeMax: 72 |
||||||
|
m_fontStyle: 0 |
||||||
|
m_HorizontalAlignment: 2 |
||||||
|
m_VerticalAlignment: 512 |
||||||
|
m_textAlignment: 65535 |
||||||
|
m_characterSpacing: 0 |
||||||
|
m_wordSpacing: 0 |
||||||
|
m_lineSpacing: 0 |
||||||
|
m_lineSpacingMax: 0 |
||||||
|
m_paragraphSpacing: 0 |
||||||
|
m_charWidthMaxAdj: 0 |
||||||
|
m_TextWrappingMode: 1 |
||||||
|
m_wordWrappingRatios: 0.4 |
||||||
|
m_overflowMode: 0 |
||||||
|
m_linkedTextComponent: {fileID: 0} |
||||||
|
parentLinkedComponent: {fileID: 0} |
||||||
|
m_enableKerning: 0 |
||||||
|
m_ActiveFontFeatures: 6e72656b |
||||||
|
m_enableExtraPadding: 0 |
||||||
|
checkPaddingRequired: 0 |
||||||
|
m_isRichText: 1 |
||||||
|
m_EmojiFallbackSupport: 1 |
||||||
|
m_parseCtrlCharacters: 1 |
||||||
|
m_isOrthographic: 1 |
||||||
|
m_isCullingEnabled: 0 |
||||||
|
m_horizontalMapping: 0 |
||||||
|
m_verticalMapping: 0 |
||||||
|
m_uvLineOffset: 0 |
||||||
|
m_geometrySortingOrder: 0 |
||||||
|
m_IsTextObjectScaleStatic: 0 |
||||||
|
m_VertexBufferAutoSizeReduction: 0 |
||||||
|
m_useMaxVisibleDescender: 1 |
||||||
|
m_pageToDisplay: 1 |
||||||
|
m_margin: {x: 0, y: 0, z: 0, w: 0} |
||||||
|
m_isUsingLegacyAnimationComponent: 0 |
||||||
|
m_isVolumetricText: 0 |
||||||
|
m_hasFontAssetChanged: 0 |
||||||
|
m_baseMaterial: {fileID: 0} |
||||||
|
m_maskOffset: {x: 0, y: 0, z: 0, w: 0} |
||||||
|
--- !u!1 &5635780241963879440 |
||||||
|
GameObject: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
serializedVersion: 6 |
||||||
|
m_Component: |
||||||
|
- component: {fileID: 6440907175184653233} |
||||||
|
- component: {fileID: 3201388121702467737} |
||||||
|
- component: {fileID: 4180124986893198757} |
||||||
|
- component: {fileID: 54520249064627873} |
||||||
|
- component: {fileID: -7838970888251817805} |
||||||
|
m_Layer: 5 |
||||||
|
m_Name: Button |
||||||
|
m_TagString: Untagged |
||||||
|
m_Icon: {fileID: 0} |
||||||
|
m_NavMeshLayer: 0 |
||||||
|
m_StaticEditorFlags: 0 |
||||||
|
m_IsActive: 1 |
||||||
|
--- !u!224 &6440907175184653233 |
||||||
|
RectTransform: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
m_GameObject: {fileID: 5635780241963879440} |
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} |
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0} |
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1} |
||||||
|
m_ConstrainProportionsScale: 0 |
||||||
|
m_Children: |
||||||
|
- {fileID: 5249829104186841453} |
||||||
|
m_Father: {fileID: 0} |
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} |
||||||
|
m_AnchorMin: {x: 0, y: 1} |
||||||
|
m_AnchorMax: {x: 0, y: 1} |
||||||
|
m_AnchoredPosition: {x: 91.5, y: -15} |
||||||
|
m_SizeDelta: {x: 183, y: 30} |
||||||
|
m_Pivot: {x: 0.5, y: 0.5} |
||||||
|
--- !u!222 &3201388121702467737 |
||||||
|
CanvasRenderer: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
m_GameObject: {fileID: 5635780241963879440} |
||||||
|
m_CullTransparentMesh: 1 |
||||||
|
--- !u!114 &4180124986893198757 |
||||||
|
MonoBehaviour: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
m_GameObject: {fileID: 5635780241963879440} |
||||||
|
m_Enabled: 1 |
||||||
|
m_EditorHideFlags: 0 |
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} |
||||||
|
m_Name: |
||||||
|
m_EditorClassIdentifier: |
||||||
|
m_Material: {fileID: 0} |
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1} |
||||||
|
m_RaycastTarget: 1 |
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} |
||||||
|
m_Maskable: 1 |
||||||
|
m_OnCullStateChanged: |
||||||
|
m_PersistentCalls: |
||||||
|
m_Calls: [] |
||||||
|
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} |
||||||
|
m_Type: 1 |
||||||
|
m_PreserveAspect: 0 |
||||||
|
m_FillCenter: 1 |
||||||
|
m_FillMethod: 4 |
||||||
|
m_FillAmount: 1 |
||||||
|
m_FillClockwise: 1 |
||||||
|
m_FillOrigin: 0 |
||||||
|
m_UseSpriteMesh: 0 |
||||||
|
m_PixelsPerUnitMultiplier: 1 |
||||||
|
--- !u!114 &54520249064627873 |
||||||
|
MonoBehaviour: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
m_GameObject: {fileID: 5635780241963879440} |
||||||
|
m_Enabled: 1 |
||||||
|
m_EditorHideFlags: 0 |
||||||
|
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} |
||||||
|
m_Name: |
||||||
|
m_EditorClassIdentifier: |
||||||
|
m_Navigation: |
||||||
|
m_Mode: 3 |
||||||
|
m_WrapAround: 0 |
||||||
|
m_SelectOnUp: {fileID: 0} |
||||||
|
m_SelectOnDown: {fileID: 0} |
||||||
|
m_SelectOnLeft: {fileID: 0} |
||||||
|
m_SelectOnRight: {fileID: 0} |
||||||
|
m_Transition: 1 |
||||||
|
m_Colors: |
||||||
|
m_NormalColor: {r: 1, g: 1, b: 1, a: 1} |
||||||
|
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} |
||||||
|
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} |
||||||
|
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} |
||||||
|
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} |
||||||
|
m_ColorMultiplier: 1 |
||||||
|
m_FadeDuration: 0.1 |
||||||
|
m_SpriteState: |
||||||
|
m_HighlightedSprite: {fileID: 0} |
||||||
|
m_PressedSprite: {fileID: 0} |
||||||
|
m_SelectedSprite: {fileID: 0} |
||||||
|
m_DisabledSprite: {fileID: 0} |
||||||
|
m_AnimationTriggers: |
||||||
|
m_NormalTrigger: Normal |
||||||
|
m_HighlightedTrigger: Highlighted |
||||||
|
m_PressedTrigger: Pressed |
||||||
|
m_SelectedTrigger: Selected |
||||||
|
m_DisabledTrigger: Disabled |
||||||
|
m_Interactable: 1 |
||||||
|
m_TargetGraphic: {fileID: 4180124986893198757} |
||||||
|
m_OnClick: |
||||||
|
m_PersistentCalls: |
||||||
|
m_Calls: [] |
||||||
|
--- !u!114 &-7838970888251817805 |
||||||
|
MonoBehaviour: |
||||||
|
m_ObjectHideFlags: 0 |
||||||
|
m_CorrespondingSourceObject: {fileID: 0} |
||||||
|
m_PrefabInstance: {fileID: 0} |
||||||
|
m_PrefabAsset: {fileID: 0} |
||||||
|
m_GameObject: {fileID: 5635780241963879440} |
||||||
|
m_Enabled: 1 |
||||||
|
m_EditorHideFlags: 0 |
||||||
|
m_Script: {fileID: 11500000, guid: 74056c96f6b34045924a42030d0ba1f9, type: 3} |
||||||
|
m_Name: |
||||||
|
m_EditorClassIdentifier: |
||||||
|
EnableMessage: 0 |
||||||
|
button: {fileID: 54520249064627873} |
@ -0,0 +1,7 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 42fa37d0d62c2c649ad2a46cd6042baa |
||||||
|
PrefabImporter: |
||||||
|
externalObjects: {} |
||||||
|
userData: |
||||||
|
assetBundleName: |
||||||
|
assetBundleVariant: |
@ -0,0 +1,33 @@ |
|||||||
|
using UnityEngine; |
||||||
|
using UnityEngine.UI; |
||||||
|
|
||||||
|
namespace Tools.EasyPoolKit.Demo |
||||||
|
{ |
||||||
|
public class ImageButton : RecyclableMonoBehaviour |
||||||
|
{ |
||||||
|
[SerializeField] private Button button; |
||||||
|
|
||||||
|
public override void OnObjectInit() |
||||||
|
{ |
||||||
|
base.OnObjectInit(); |
||||||
|
button.onClick.AddListener(OnClick); |
||||||
|
} |
||||||
|
|
||||||
|
public override void OnObjectSpawn() |
||||||
|
{ |
||||||
|
base.OnObjectSpawn(); |
||||||
|
Debug.Log($"ImageButton Spawned {name}"); |
||||||
|
} |
||||||
|
|
||||||
|
public override void OnObjectDespawn() |
||||||
|
{ |
||||||
|
base.OnObjectDespawn(); |
||||||
|
Debug.Log($"ImageButton Despawn {name}"); |
||||||
|
} |
||||||
|
|
||||||
|
private void OnClick() |
||||||
|
{ |
||||||
|
Debug.Log($"Button Clicked {name}"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 74056c96f6b34045924a42030d0ba1f9 |
||||||
|
timeCreated: 1735967055 |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@ |
|||||||
|
fileFormatVersion: 2 |
||||||
|
guid: 5f9a4efcfd104ae42a4bd7e35bc1d016 |
||||||
|
DefaultImporter: |
||||||
|
externalObjects: {} |
||||||
|
userData: |
||||||
|
assetBundleName: |
||||||
|
assetBundleVariant: |
@ -0,0 +1,56 @@ |
|||||||
|
using System; |
||||||
|
using UnityEngine; |
||||||
|
|
||||||
|
namespace Tools.EasyPoolKit.Demo |
||||||
|
{ |
||||||
|
public class RecyclableGOPoolManager : MonoBehaviour |
||||||
|
{ |
||||||
|
[SerializeField] private GameObject buttonPrefab; |
||||||
|
|
||||||
|
[SerializeField] private Transform parent; |
||||||
|
|
||||||
|
private void Awake() |
||||||
|
{ |
||||||
|
var buttonConfig = new RecyclablePoolConfig() |
||||||
|
{ |
||||||
|
ObjectType = RecycleObjectType.RecyclableGameObject, |
||||||
|
ReferenceType = typeof(ImageButton), |
||||||
|
PoolId = "ImageButtonPool", |
||||||
|
InitCreateCount = 5, |
||||||
|
ReachMaxLimitType = PoolReachMaxLimitType.RecycleOldest, |
||||||
|
MaxSpawnCount = 10, |
||||||
|
DespawnDestroyType = PoolDespawnDestroyType.DestroyToLimit, |
||||||
|
MaxDespawnCount = 5, |
||||||
|
ClearType = PoolClearType.ClearToLimit, |
||||||
|
IsIgnoreTimeScale = false, |
||||||
|
}; |
||||||
|
RecyclableGOPoolKit.Instance.RegisterPrefab(buttonPrefab, buttonConfig); |
||||||
|
} |
||||||
|
|
||||||
|
private void Update() |
||||||
|
{ |
||||||
|
if (Input.GetKeyDown(KeyCode.A)) |
||||||
|
{ |
||||||
|
var newImage = RecyclableGOPoolKit.Instance.SimpleSpawn<ImageButton>(buttonPrefab); |
||||||
|
newImage.transform.SetParent(parent); |
||||||
|
} |
||||||
|
// else if (Input.GetKeyDown(KeyCode.S)) |
||||||
|
// { |
||||||
|
// RecyclableGOPoolKit.Instance.Despawn("Image"); |
||||||
|
// } |
||||||
|
// else if (Input.GetKeyDown(KeyCode.C)) |
||||||
|
// { |
||||||
|
// RecyclableGOPoolKit.Instance.ClearAllPools(true); |
||||||
|
// } |
||||||
|
// else if (Input.GetKeyDown(KeyCode.Alpha1)) |
||||||
|
// { |
||||||
|
// var newImage = RecyclableGOPoolKit.Instance.Spawn("Cube"); |
||||||
|
// newImage.transform.SetParent(null); |
||||||
|
// } |
||||||
|
// else if (Input.GetKeyDown(KeyCode.Alpha2)) |
||||||
|
// { |
||||||
|
// RecyclableGOPoolKit.Instance.Despawn("Cube"); |
||||||
|
// } |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue