ObjectPool

ObjectPool
This commit is contained in:
ALEXTANG
2022-09-04 17:11:10 +08:00
parent 7f3b8efbd8
commit cddb45b654
15 changed files with 883 additions and 0 deletions

View File

@@ -1,5 +1,49 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1672025513
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1672025514}
- component: {fileID: 1672025515}
m_Layer: 0
m_Name: ObjectPool
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1672025514
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1672025513}
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_Children: []
m_Father: {fileID: 3463045026180535779}
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1672025515
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1672025513}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bef095b963a40b54fa82ba105bd1e98e, type: 3}
m_Name:
m_EditorClassIdentifier:
Limit: 100
--- !u!1 &3463045025307533287
GameObject:
m_ObjectHideFlags: 0
@@ -290,6 +334,7 @@ Transform:
- {fileID: 3463045025836799505}
- {fileID: 3463045026010536331}
- {fileID: 3463045025307533286}
- {fileID: 1672025514}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

View File

@@ -0,0 +1,41 @@
using TEngine.Runtime;
using UnityEditor;
using UnityEngine;
namespace TEngine.Editor
{
[CustomEditor(typeof(ObjectPoolManager))]
internal sealed class ObjectPoolManagerInspector : TEngineInspector
{
public override void OnInspectorGUI()
{
if (!EditorApplication.isPlaying)
{
EditorGUILayout.HelpBox("Available during runtime only.", MessageType.Info);
return;
}
if (ObjectPoolManager.Instance.Helper.ObjectPools.Count == 0)
{
GUILayout.BeginHorizontal();
GUILayout.Label("No Runtime Data!");
GUILayout.EndHorizontal();
}
foreach (var pool in ObjectPoolManager.Instance.Helper.ObjectPools)
{
GUILayout.BeginHorizontal();
GUILayout.Space(20);
GUILayout.Label(pool.Key + ": " + pool.Value.Count);
GUILayout.FlexibleSpace();
GUI.enabled = pool.Value.Count > 0;
if (GUILayout.Button("Clear", EditorStyles.miniButton))
{
pool.Value.Clear();
}
GUI.enabled = true;
GUILayout.EndHorizontal();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a49fa7335fa305d4bbef4478b39ed39a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,180 @@
using System.Collections.Generic;
using UnityEngine;
namespace TEngine.Runtime
{
public static partial class Utility
{
/// <summary>
/// GameObject相关的实用函数。
/// </summary>
public static class GameObjectUtils
{
#region Static Method
/// <summary>
/// 克隆实例
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <param name="original">初始对象</param>
/// <returns>克隆的新对象</returns>
public static T Clone<T>(T original) where T : Object
{
return Object.Instantiate(original);
}
/// <summary>
/// 克隆实例
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <param name="original">初始对象</param>
/// <param name="position">新对象的位置</param>
/// <param name="rotation">新对象的旋转</param>
/// <returns>克隆的新对象</returns>
public static T Clone<T>(T original, Vector3 position, Quaternion rotation) where T : Object
{
return Object.Instantiate(original, position, rotation);
}
/// <summary>
/// 克隆实例
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <param name="original">初始对象</param>
/// <param name="position">新对象的位置</param>
/// <param name="rotation">新对象的旋转</param>
/// <param name="parent">新对象的父物体</param>
/// <returns>克隆的新对象</returns>
public static T Clone<T>(T original, Vector3 position, Quaternion rotation, Transform parent)
where T : Object
{
return Object.Instantiate(original, position, rotation, parent);
}
/// <summary>
/// 克隆实例
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <param name="original">初始对象</param>
/// <param name="parent">新对象的父物体</param>
/// <returns>克隆的新对象</returns>
public static T Clone<T>(T original, Transform parent) where T : Object
{
return Object.Instantiate(original, parent);
}
/// <summary>
/// 克隆实例
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <param name="original">初始对象</param>
/// <param name="parent">新对象的父物体</param>
/// <param name="worldPositionStays">是否保持世界位置不变</param>
/// <returns>克隆的新对象</returns>
public static T Clone<T>(T original, Transform parent, bool worldPositionStays) where T : Object
{
return Object.Instantiate(original, parent, worldPositionStays);
}
/// <summary>
/// 克隆 GameObject 实例
/// </summary>
/// <param name="original">初始对象</param>
/// <param name="isUI">是否是UI对象</param>
/// <returns>克隆的新对象</returns>
public static GameObject CloneGameObject(GameObject original, bool isUI = false)
{
GameObject obj = Object.Instantiate(original);
obj.transform.SetParent(original.transform.parent);
if (isUI)
{
RectTransform rect = obj.rectTransform();
RectTransform originalRect = original.rectTransform();
rect.anchoredPosition3D = originalRect.anchoredPosition3D;
rect.sizeDelta = originalRect.sizeDelta;
rect.offsetMin = originalRect.offsetMin;
rect.offsetMax = originalRect.offsetMax;
rect.anchorMin = originalRect.anchorMin;
rect.anchorMax = originalRect.anchorMax;
rect.pivot = originalRect.pivot;
}
else
{
obj.transform.localPosition = original.transform.localPosition;
}
obj.transform.localRotation = original.transform.localRotation;
obj.transform.localScale = original.transform.localScale;
obj.SetActive(true);
return obj;
}
/// <summary>
/// 杀死实例
/// </summary>
/// <param name="obj">实例对象</param>
public static void Kill(Object obj)
{
Object.Destroy(obj);
}
/// <summary>
/// 立即杀死实例
/// </summary>
/// <param name="obj">实例对象</param>
public static void KillImmediate(Object obj)
{
Object.DestroyImmediate(obj);
}
/// <summary>
/// 杀死一群实例
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <param name="objs">实例集合</param>
public static void Kills<T>(List<T> objs) where T : Object
{
for (int i = 0; i < objs.Count; i++)
{
Object.Destroy(objs[i]);
}
objs.Clear();
}
/// <summary>
/// 杀死一群实例
/// </summary>
/// <typeparam name="T">实例类型</typeparam>
/// <param name="objs">实例数组</param>
public static void Kills<T>(T[] objs) where T : Object
{
for (int i = 0; i < objs.Length; i++)
{
Object.Destroy(objs[i]);
}
}
#endregion
}
}
public static class GameObjectExt
{
/// <summary>
/// 获取RectTransform组件
/// </summary>
public static RectTransform rectTransform(this GameObject obj)
{
return obj.GetComponent<RectTransform>();
}
/// <summary>
/// 获取RectTransform组件
/// </summary>
public static RectTransform rectTransform(this MonoBehaviour mono)
{
return mono.GetComponent<RectTransform>();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8a631f70e55a4d419de768a51347edab
timeCreated: 1662280007

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 18905312db3bc3d448630110b4a9bcd3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: eaa7867dbaa447e42b63eb98f3dd8687
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,221 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TEngine.Runtime
{
/// <summary>
/// 默认的对象池管理器助手
/// </summary>
public sealed class DefaultObjectPoolHelper : IObjectPoolHelper
{
/// <summary>
/// 对象池默认上限
/// </summary>
private int _limit;
/// <summary>
/// 所有对象池
/// </summary>
public Dictionary<string, ObjectPool> ObjectPools { get; private set; } =
new Dictionary<string, ObjectPool>();
/// <summary>
/// 初始化助手
/// </summary>
public DefaultObjectPoolHelper()
{
_limit = ObjectPoolManager.Instance.Limit;
}
/// <summary>
/// ShutDown
/// </summary>
public void ShutDown()
{
ClearAll();
}
/// <summary>
/// 注册对象池
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="allocItem">对象模板</param>
/// <param name="onAlloc">对象生成时初始化委托</param>
/// <param name="onRelease">对象回收时处理委托</param>
/// <param name="limit">对象池上限等于0时表示使用默认值</param>
public void RegisterPool(string name, GameObject allocItem, Action<GameObject> onAlloc,
Action<GameObject> onRelease, int limit)
{
if (allocItem == null)
return;
if (!ObjectPools.ContainsKey(name))
{
ObjectPools.Add(name, new ObjectPool(allocItem, limit <= 0 ? _limit : limit, onAlloc, onRelease));
}
else
{
Log.Error("注册对象池失败:已存在对象池 " + name + " ");
}
}
/// <summary>
/// 是否存在指定名称的对象池
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>是否存在</returns>
public bool IsExistPool(string name)
{
return ObjectPools.ContainsKey(name);
}
/// <summary>
/// 移除已注册的对象池
/// </summary>
/// <param name="name">对象池名称</param>
public void UnRegisterPool(string name)
{
if (ObjectPools.ContainsKey(name))
{
ObjectPools[name].Clear();
ObjectPools.Remove(name);
}
else
{
Log.Error("移除对象池失败:不存在对象池 " + name + " ");
}
}
/// <summary>
/// 获取对象池中对象数量
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>对象数量</returns>
public int GetPoolCount(string name)
{
if (ObjectPools.ContainsKey(name))
{
return ObjectPools[name].Count;
}
else
{
Log.Warning("获取对象数量失败:不存在对象池 " + name + " ");
return 0;
}
}
/// <summary>
/// 生成对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>对象</returns>
public GameObject Alloc(string name)
{
if (ObjectPools.ContainsKey(name))
{
return ObjectPools[name].Alloc();
}
else
{
Log.Error("生成对象失败:不存在对象池 " + name + " ");
return null;
}
}
/// <summary>
/// 回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="target">对象</param>
public void Release(string name, GameObject target)
{
if (target == null)
return;
if (ObjectPools.ContainsKey(name))
{
ObjectPools[name].Release(target);
}
else
{
Log.Error("回收对象失败:不存在对象池 " + name + " ");
}
}
/// <summary>
/// 批量回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="targets">对象数组</param>
public void Releases(string name, GameObject[] targets)
{
if (targets == null)
return;
if (ObjectPools.ContainsKey(name))
{
for (int i = 0; i < targets.Length; i++)
{
ObjectPools[name].Release(targets[i]);
}
}
else
{
Log.Error("回收对象失败:不存在对象池 " + name + " ");
}
}
/// <summary>
/// 批量回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="targets">对象集合</param>
public void Releases(string name, List<GameObject> targets)
{
if (targets == null)
return;
if (ObjectPools.ContainsKey(name))
{
for (int i = 0; i < targets.Count; i++)
{
ObjectPools[name].Release(targets[i]);
}
targets.Clear();
}
else
{
Log.Error("回收对象失败:不存在对象池 " + name + " ");
}
}
/// <summary>
/// 清空指定的对象池
/// </summary>
/// <param name="name">对象池名称</param>
public void Clear(string name)
{
if (ObjectPools.ContainsKey(name))
{
ObjectPools[name].Clear();
}
else
{
Log.Error("清空对象池失败:不存在对象池 " + name + " ");
}
}
/// <summary>
/// 清空所有对象池
/// </summary>
public void ClearAll()
{
foreach (var pool in ObjectPools)
{
pool.Value.Clear();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f19a0d9040fd24439a22aa1b33b1752
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 701b9bfeb6deef341a599f8d0f1ec080, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TEngine.Runtime
{
/// <summary>
/// 对象池管理器的助手接口
/// </summary>
public interface IObjectPoolHelper
{
/// <summary>
/// 所有对象池
/// </summary>
Dictionary<string, ObjectPool> ObjectPools { get; }
/// <summary>
/// 注册对象池
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="allocItem">对象模板</param>
/// <param name="onAlloc">对象生成时初始化委托</param>
/// <param name="onRelease">对象回收时处理委托</param>
/// <param name="limit">对象池上限等于0时表示使用默认值</param>
void RegisterPool(string name, GameObject allocItem, Action<GameObject> onAlloc,
Action<GameObject> onRelease, int limit);
/// <summary>
/// 是否存在指定名称的对象池
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>是否存在</returns>
bool IsExistPool(string name);
/// <summary>
/// 移除已注册的对象池
/// </summary>
/// <param name="name">对象池名称</param>
void UnRegisterPool(string name);
/// <summary>
/// 获取对象池中对象数量
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>对象数量</returns>
int GetPoolCount(string name);
/// <summary>
/// 生成对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>对象</returns>
GameObject Alloc(string name);
/// <summary>
/// 回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="target">对象</param>
void Release(string name, GameObject target);
/// <summary>
/// 批量回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="targets">对象数组</param>
void Releases(string name, GameObject[] targets);
/// <summary>
/// 批量回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="targets">对象集合</param>
void Releases(string name, List<GameObject> targets);
/// <summary>
/// 清空指定的对象池
/// </summary>
/// <param name="name">对象池名称</param>
void Clear(string name);
/// <summary>
/// 清空所有对象池
/// </summary>
void ClearAll();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f0af4beea5247d40a447b27c807de3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 701b9bfeb6deef341a599f8d0f1ec080, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TEngine.Runtime
{
/// <summary>
/// 对象池
/// </summary>
public sealed class ObjectPool
{
private readonly GameObject _allocItem;
private readonly int _limit = 100;
private readonly Queue<GameObject> _objectQueue = new Queue<GameObject>();
private readonly Action<GameObject> _onAlloc;
private readonly Action<GameObject> _onRelease;
/// <summary>
/// 对象数量
/// </summary>
public int Count
{
get { return _objectQueue.Count; }
}
/// <summary>
/// 构造函数对象池
/// </summary>
/// <param name="allocItem"></param>
/// <param name="limit"></param>
/// <param name="onAlloc"></param>
/// <param name="onRelease"></param>
public ObjectPool(GameObject allocItem, int limit, Action<GameObject> onAlloc,
Action<GameObject> onRelease)
{
_allocItem = allocItem;
_limit = limit;
_onAlloc = onAlloc;
_onRelease = onRelease;
}
/// <summary>
/// 生成对象
/// </summary>
/// <returns>对象</returns>
public GameObject Alloc()
{
GameObject obj;
if (_objectQueue.Count > 0)
{
obj = _objectQueue.Dequeue();
}
else
{
obj = Utility.GameObjectUtils.CloneGameObject(_allocItem);
}
obj.SetActive(true);
obj.transform.SetParent(null);
_onAlloc?.Invoke(obj);
return obj;
}
/// <summary>
/// 回收对象
/// </summary>
/// <param name="obj">对象</param>
public void Release(GameObject obj)
{
if (_objectQueue.Count >= _limit)
{
_onRelease?.Invoke(obj);
Utility.GameObjectUtils.Kill(obj);
}
else
{
obj.SetActive(false);
_onRelease?.Invoke(obj);
_objectQueue.Enqueue(obj);
obj.transform.SetParent(ObjectPoolManager.Instance.gameObject.transform);
}
}
/// <summary>
/// 清空所有对象
/// </summary>
public void Clear()
{
while (_objectQueue.Count > 0)
{
GameObject obj = _objectQueue.Dequeue();
if (obj)
{
Utility.GameObjectUtils.Kill(obj);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 27382aff833de094e97dd246ad567aad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 701b9bfeb6deef341a599f8d0f1ec080, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TEngine.Runtime
{
/// <summary>
/// 对象池管理器
/// </summary>
public sealed class ObjectPoolManager : UnitySingleton<ObjectPoolManager>
{
private IObjectPoolHelper _helper;
public IObjectPoolHelper Helper => _helper;
public override int Priority => -1;
public override void Awake()
{
base.Awake();
_helper = new DefaultObjectPoolHelper();
}
/// <summary>
/// 单个对象池上限
/// </summary>
[SerializeField] internal int Limit = 100;
/// <summary>
/// 注册对象池
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="allocItem">对象模板</param>
/// <param name="onAlloc">对象生成时初始化委托</param>
/// <param name="onRelease">对象回收时处理委托</param>
/// <param name="limit">对象池上限等于0时表示使用默认值</param>
public void RegisterPool(string name, GameObject allocItem, Action<GameObject> onAlloc = null,
Action<GameObject> onRelease = null, int limit = 0)
{
_helper.RegisterPool(name, allocItem, onAlloc, onRelease, limit);
}
/// <summary>
/// 是否存在指定名称的对象池
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>是否存在</returns>
public bool IsExistPool(string name)
{
return _helper.IsExistPool(name);
}
/// <summary>
/// 移除已注册的对象池
/// </summary>
/// <param name="name">对象池名称</param>
public void UnRegisterPool(string name)
{
_helper.UnRegisterPool(name);
}
/// <summary>
/// 获取对象池中对象数量
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>对象数量</returns>
public int GetPoolCount(string name)
{
return _helper.GetPoolCount(name);
}
/// <summary>
/// 生成对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <returns>对象</returns>
public GameObject Alloc(string name)
{
return _helper.Alloc(name);
}
/// <summary>
/// 回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="target">对象</param>
public void Release(string name, GameObject target)
{
_helper.Release(name, target);
}
/// <summary>
/// 批量回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="targets">对象数组</param>
public void Releases(string name, GameObject[] targets)
{
_helper.Releases(name, targets);
}
/// <summary>
/// 批量回收对象
/// </summary>
/// <param name="name">对象池名称</param>
/// <param name="targets">对象集合</param>
public void Releases(string name, List<GameObject> targets)
{
_helper.Releases(name, targets);
}
/// <summary>
/// 清空指定的对象池
/// </summary>
/// <param name="name">对象池名称</param>
public void Clear(string name)
{
_helper.Clear(name);
}
/// <summary>
/// 清空所有对象池
/// </summary>
public void ClearAll()
{
_helper.ClearAll();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bef095b963a40b54fa82ba105bd1e98e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: