|  |  |  | 
|---|
|  |  |  | using System.Collections.Generic; | 
|---|
|  |  |  | using UnityEngine; | 
|---|
|  |  |  | using System; | 
|---|
|  |  |  | using Cysharp.Threading.Tasks; | 
|---|
|  |  |  | using System.Linq; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | using UnityEngine.Profiling; | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public class GameObjectPoolManager : SingletonMonobehaviour<GameObjectPoolManager> | 
|---|
|  |  |  | { | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | private Dictionary<int, DebugItem> m_DebugInstIDDict = null; | 
|---|
|  |  |  | private bool m_ShowDebugPanel = false; | 
|---|
|  |  |  | private Vector2 m_ScrollPosition = Vector2.zero; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private void OnGUI() | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if (!m_ShowDebugPanel) return; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | GUILayout.BeginArea(new Rect(10, 10, 400, 600)); | 
|---|
|  |  |  | GUILayout.BeginVertical("Box"); | 
|---|
|  |  |  | m_ScrollPosition = GUILayout.BeginScrollView(m_ScrollPosition, GUILayout.Width(380), GUILayout.Height(580)); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | GUILayout.Label("对象池调试面板", GUILayout.Height(30)); | 
|---|
|  |  |  | LogPoolMemoryUsage(); | 
|---|
|  |  |  | GUILayout.Space(10); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | foreach (var poolEntry in m_PoolDict) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | int prefabInstanceId = poolEntry.Key; | 
|---|
|  |  |  | GameObjectPool pool = poolEntry.Value; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | GUILayout.BeginVertical("Box"); | 
|---|
|  |  |  | GUILayout.Label($"池名称: {pool.Prefab.name}"); | 
|---|
|  |  |  | GUILayout.Label($"活跃对象数: {pool.m_ActiveHashSet.Count}"); | 
|---|
|  |  |  | GUILayout.Label($"空闲对象数: {pool.m_FreeQueue.Count}"); | 
|---|
|  |  |  | int count = m_PoolUsageFrequency.TryGetValue(prefabInstanceId, out int frequency) ? frequency : 0; | 
|---|
|  |  |  | GUILayout.Label($"使用频率: {count}"); | 
|---|
|  |  |  | GUILayout.EndVertical(); | 
|---|
|  |  |  | GUILayout.Space(5); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | GUILayout.EndScrollView(); | 
|---|
|  |  |  | GUILayout.EndVertical(); | 
|---|
|  |  |  | GUILayout.EndArea(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | [UnityEditor.MenuItem("Tools/对象池/显示调试面板")] | 
|---|
|  |  |  | private static void ToggleDebugPanel() | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if (Instance != null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Instance.m_ShowDebugPanel = !Instance.m_ShowDebugPanel; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void LogPoolMemoryUsage() | 
|---|
|  |  |  | { | 
|---|
|  |  |  | long totalMemory = 0; | 
|---|
|  |  |  | long totalFreeMemory = 0; | 
|---|
|  |  |  | var prefabMemoryDict = new Dictionary<string, long>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | foreach (var poolEntry in m_PoolDict) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | int prefabInstanceId = poolEntry.Key; | 
|---|
|  |  |  | GameObjectPool pool = poolEntry.Value; | 
|---|
|  |  |  | string prefabName = pool.Prefab.name; | 
|---|
|  |  |  | long prefabMemory = 0; | 
|---|
|  |  |  | long freeMemory = 0; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 计算活跃对象的内存占用 | 
|---|
|  |  |  | foreach (var gameObject in pool.m_ActiveHashSet) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if (gameObject != null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | long memory = Profiler.GetRuntimeMemorySizeLong(gameObject); | 
|---|
|  |  |  | prefabMemory += memory; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 计算空闲对象的内存占用 | 
|---|
|  |  |  | foreach (var gameObject in pool.m_FreeQueue) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if (gameObject != null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | long memory = Profiler.GetRuntimeMemorySizeLong(gameObject); | 
|---|
|  |  |  | prefabMemory += memory; | 
|---|
|  |  |  | freeMemory += memory; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | totalMemory += prefabMemory; | 
|---|
|  |  |  | totalFreeMemory += freeMemory; | 
|---|
|  |  |  | prefabMemoryDict[prefabName] = prefabMemory; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 按内存占用排序 | 
|---|
|  |  |  | var sortedPrefabs = prefabMemoryDict.OrderByDescending(kv => kv.Value).Take(3).ToList(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | GUILayout.Label($"总内存占用: {totalMemory / 1024} KB", GUILayout.Height(30)); | 
|---|
|  |  |  | GUILayout.Label($"空闲内存占用: {totalFreeMemory / 1024} KB", GUILayout.Height(30)); | 
|---|
|  |  |  | GUILayout.Label("占用最高的前3预制体名:", GUILayout.Height(30)); | 
|---|
|  |  |  | foreach (var prefabInstance in sortedPrefabs) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | GUILayout.BeginHorizontal("Box"); | 
|---|
|  |  |  | GUILayout.Label($"{prefabInstance.Key}({prefabInstance.Value / 1024} KB)", GUILayout.Height(25)); | 
|---|
|  |  |  | GUILayout.EndHorizontal(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  | // 池统计数据 | 
|---|
|  |  |  | public Dictionary<int, PoolStats> PoolStatistics { get; private set; } = new Dictionary<int, PoolStats>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public class PoolStats | 
|---|
|  |  |  | { | 
|---|
|  |  |  | public int TotalObjects { get; set; } | 
|---|
|  |  |  | public int ActiveObjects { get; set; } | 
|---|
|  |  |  | public int FreeObjects { get; set; } | 
|---|
|  |  |  | public int UsageFrequency { get; set; } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 更新池统计数据 | 
|---|
|  |  |  | private void UpdatePoolStats() | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if (m_PoolDict == null) | 
|---|
|  |  |  | return; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | foreach (var poolEntry in m_PoolDict) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | int prefabInstanceId = poolEntry.Key; | 
|---|
|  |  |  | GameObjectPool pool = poolEntry.Value; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!PoolStatistics.ContainsKey(prefabInstanceId)) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | PoolStatistics[prefabInstanceId] = new PoolStats(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | PoolStats stats = PoolStatistics[prefabInstanceId]; | 
|---|
|  |  |  | stats.TotalObjects = pool.m_ActiveHashSet.Count + pool.m_FreeQueue.Count; | 
|---|
|  |  |  | stats.ActiveObjects = pool.m_ActiveHashSet.Count; | 
|---|
|  |  |  | stats.FreeObjects = pool.m_FreeQueue.Count; | 
|---|
|  |  |  | stats.UsageFrequency = m_PoolUsageFrequency.TryGetValue(prefabInstanceId, out int frequency) ? frequency : 0; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private Dictionary<int, GameObjectPool> m_PoolDict = null; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 不需要销毁的对象列表 | 
|---|
|  |  |  | private List<int> dontDestoryGoInstIDList = null; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private Transform m_TargetContainer; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 定期检查池的时间间隔(秒) | 
|---|
|  |  |  | private float m_PoolCheckInterval = 600f; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 记录每个池的使用频率 | 
|---|
|  |  |  | private Dictionary<int, int> m_PoolUsageFrequency = new Dictionary<int, int>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //需要动态卸载的预制体,例如切换场景时 | 
|---|
|  |  |  | public List<GameObject> needDestroyPrefabList = new List<GameObject>(); | 
|---|
|  |  |  | 
|---|
|  |  |  | dontDestoryGoInstIDList = new List<int>(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | if (m_DebugInstIDDict == null) | 
|---|
|  |  |  | // 启动定期检查池的协程 | 
|---|
|  |  |  | CheckPoolUsage(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private async UniTask CheckPoolUsage() | 
|---|
|  |  |  | { | 
|---|
|  |  |  | while (true) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | m_DebugInstIDDict = new Dictionary<int, DebugItem>(); | 
|---|
|  |  |  | await UniTask.Delay(TimeSpan.FromSeconds(m_PoolCheckInterval)); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | foreach (var poolEntry in m_PoolDict) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | int prefabInstanceId = poolEntry.Key; | 
|---|
|  |  |  | GameObjectPool pool = poolEntry.Value; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 如果池的使用频率低于阈值,减少池的大小 | 
|---|
|  |  |  | if (m_PoolUsageFrequency.TryGetValue(prefabInstanceId, out int usageCount) && usageCount < 5) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | // 保留至少一个对象,避免频繁创建和销毁 | 
|---|
|  |  |  | int targetSize = Mathf.Max(1, pool.m_FreeQueue.Count / 2); | 
|---|
|  |  |  | while (pool.m_FreeQueue.Count > targetSize) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | GameObject obj = pool.m_FreeQueue.Dequeue(); | 
|---|
|  |  |  | if (!dontDestoryGoInstIDList.Contains(obj.GetInstanceID())) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Destroy(obj); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 重置使用频率 | 
|---|
|  |  |  | m_PoolUsageFrequency[prefabInstanceId] = 0; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void AddDontDestroyGoInstID(int id) | 
|---|
|  |  |  | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /// <summary> | 
|---|
|  |  |  | /// 传入的为预制体,而非组件,否则会导致GetInstanceID管理混乱,每次实例化都会改变 | 
|---|
|  |  |  | /// </summary> | 
|---|
|  |  |  | /// <param name="prefab"></param> | 
|---|
|  |  |  | /// <returns></returns> | 
|---|
|  |  |  | public GameObjectPool RequestPool(GameObject prefab) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if (prefab == null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | if (UnityEditor.PrefabUtility.GetPrefabAssetType(prefab) == UnityEditor.PrefabAssetType.NotAPrefab) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Debug.LogError($"{prefab.name}不是一个预制体!"); | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int _prefabInstanceId = prefab.GetInstanceID(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | if (UnityEditor.PrefabUtility.GetPrefabAssetType(prefab) == UnityEditor.PrefabAssetType.NotAPrefab) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Debug.LogError($"{prefab.name}不是一个预制体!"); | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  | return RequestPool(prefab).Request(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //特定情况下需要动态卸载的,如切换场景时 | 
|---|
|  |  |  | public void UnLoadAll(bool force = false) | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public HashSet<GameObject> m_ActiveHashSet = new HashSet<GameObject>(); | 
|---|
|  |  |  | private Queue<GameObject> m_FreeQueue = null; | 
|---|
|  |  |  | private int Pool_FreeList_Warning_Threshold = 8; | 
|---|
|  |  |  | public Queue<GameObject> m_FreeQueue = null; | 
|---|
|  |  |  | private int Pool_FreeList_Warning_Threshold = 10;    //当空闲对象高于此值时,会进行日志输出提醒 | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Action<GameObject> releaseCallBack; | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | private Transform m_DebugContainer; | 
|---|
|  |  |  | private Transform m_DebugActive; | 
|---|
|  |  |  | private Transform m_DebugFree; | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public string assetBundleName; | 
|---|
|  |  |  | public string assetName; | 
|---|
|  |  |  | 
|---|
|  |  |  | m_ActiveHashSet = new HashSet<GameObject>(); | 
|---|
|  |  |  | m_FreeQueue = new Queue<GameObject>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | m_DebugContainer = new GameObject(prefab.name).transform; | 
|---|
|  |  |  | m_DebugActive = new GameObject("Active").transform; | 
|---|
|  |  |  | m_DebugFree = new GameObject("Free").transform; | 
|---|
|  |  |  | m_DebugActive.SetParent(m_DebugContainer); | 
|---|
|  |  |  | m_DebugFree.SetParent(m_DebugContainer); | 
|---|
|  |  |  | m_DebugContainer.SetParent(Instance.transform); | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void AddReleaseListener(Action<GameObject> _callBack) | 
|---|
|  |  |  | 
|---|
|  |  |  | _go.transform.position = Constants.Special_Hide_Position; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | // 检查空闲列表数量是否超过阈值 | 
|---|
|  |  |  | if (m_FreeList.Count > Pool_FreeList_Warning_Threshold) | 
|---|
|  |  |  | if (m_FreeQueue.Count > Pool_FreeList_Warning_Threshold) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Debug.LogWarning($"GameObjectPool {m_Prefab.name} 的空闲对象数量 ({m_FreeList.Count}) 超过阈值 ({Pool_FreeList_Warning_Threshold}),请检查是否需要清理。"); | 
|---|
|  |  |  | Debug.LogWarning($"GameObjectPool {m_Prefab.name} 的空闲对象数量 ({m_FreeQueue.Count}) 超过阈值 ({Pool_FreeList_Warning_Threshold}),请检查是否需要清理。"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | DebugItem _debugItem = new GameObject(_go.GetInstanceID().ToString()).AddMissingComponent<DebugItem>(); | 
|---|
|  |  |  | _debugItem.transform.SetParent(m_DebugFree); | 
|---|
|  |  |  | _debugItem.target = _go; | 
|---|
|  |  |  | Instance.m_DebugInstIDDict[_go.GetInstanceID()] = _debugItem; | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  | var animator = _go.GetComponent<Animator>(); | 
|---|
|  |  |  | if (animator != null) | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | m_ActiveHashSet.Add(_go); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | if (Instance.m_DebugInstIDDict.ContainsKey(_go.GetInstanceID())) | 
|---|
|  |  |  | // 统计池的使用频率 | 
|---|
|  |  |  | if (Instance.m_PoolUsageFrequency.ContainsKey(m_Prefab.GetInstanceID())) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | DebugItem _debugItem = Instance.m_DebugInstIDDict[_go.GetInstanceID()]; | 
|---|
|  |  |  | _debugItem.transform.SetParent(m_DebugActive); | 
|---|
|  |  |  | Instance.m_PoolUsageFrequency[m_Prefab.GetInstanceID()]++; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  | else | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Instance.m_PoolUsageFrequency[m_Prefab.GetInstanceID()] = 1; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | _go = Instantiate(m_Prefab, Constants.Special_Hide_Position, Quaternion.identity); | 
|---|
|  |  |  | m_ActiveHashSet.Add(_go); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | DebugItem _debugItem = new GameObject(_go.GetInstanceID().ToString()).AddMissingComponent<DebugItem>(); | 
|---|
|  |  |  | _debugItem.transform.SetParent(m_DebugActive); | 
|---|
|  |  |  | _debugItem.target = _go; | 
|---|
|  |  |  | Instance.m_DebugInstIDDict[_go.GetInstanceID()] = _debugItem; | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | _go.transform.SetParent(null); | 
|---|
|  |  |  | _go.transform.localScale = Vector3.one; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 更新池统计数据 | 
|---|
|  |  |  | Instance.UpdatePoolStats(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return _go; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void Release(GameObject go) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | m_FreeQueue.Enqueue(go); | 
|---|
|  |  |  | go.transform.SetParent(Instance.m_TargetContainer); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | go.transform.position = Constants.Special_Hide_Position; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | // 检查空闲列表数量是否超过阈值 | 
|---|
|  |  |  | if (m_FreeList.Count > Pool_FreeList_Warning_Threshold) | 
|---|
|  |  |  | if (m_FreeQueue.Count > Pool_FreeList_Warning_Threshold) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Debug.LogWarning($"GameObjectPool {m_Prefab.name} 的空闲对象数量 ({m_FreeList.Count}) 超过阈值 ({Pool_FreeList_Warning_Threshold}),请检查是否需要清理。"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (Instance.m_DebugInstIDDict.ContainsKey(go.GetInstanceID())) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | DebugItem _debugItem = Instance.m_DebugInstIDDict[go.GetInstanceID()]; | 
|---|
|  |  |  | _debugItem.transform.SetParent(m_DebugFree); | 
|---|
|  |  |  | Debug.LogWarning($"GameObjectPool {m_Prefab.name} 的空闲对象数量 ({m_FreeQueue.Count}) 超过阈值 ({Pool_FreeList_Warning_Threshold}),请检查是否需要清理。"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | { | 
|---|
|  |  |  | releaseCallBack(go); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 更新池统计数据 | 
|---|
|  |  |  | Instance.UpdatePoolStats(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void ReleaseAll() | 
|---|
|  |  |  | 
|---|
|  |  |  | go.transform.SetParent(Instance.m_TargetContainer); | 
|---|
|  |  |  | go.transform.position = Constants.Special_Hide_Position; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | if (Instance.m_DebugInstIDDict.ContainsKey(go.GetInstanceID())) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | DebugItem _debugItem = Instance.m_DebugInstIDDict[go.GetInstanceID()]; | 
|---|
|  |  |  | _debugItem.transform.SetParent(m_DebugFree); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  | if (releaseCallBack != null) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | releaseCallBack(go); | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  | m_ActiveHashSet.Clear(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 更新池统计数据 | 
|---|
|  |  |  | Instance.UpdatePoolStats(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void Clear() | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | if (m_ActiveHashSet.Count != 0) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Debug.LogWarningFormat("{0} 池清理后, 还有 {1} 个活跃对象. ", m_Prefab.name, m_ActiveHashSet.Count); | 
|---|
|  |  |  | 
|---|
|  |  |  | m_FreeQueue = tempQueue; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | if (m_FreeList.Count != 0) | 
|---|
|  |  |  | #if UNITY_EDITOR | 
|---|
|  |  |  | if (m_FreeQueue.Count != 0) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | Debug.LogWarningFormat("{0} 池清理后, 还有 {1} 个空闲对象. ", m_Prefab.name, m_FreeList.Count); | 
|---|
|  |  |  | Debug.LogWarningFormat("{0} 池清理后, 还有 {1} 个空闲对象. ", m_Prefab.name, m_FreeQueue.Count); | 
|---|
|  |  |  | // for (int i = 0; i < m_FreeList.Count; ++i) | 
|---|
|  |  |  | // { | 
|---|
|  |  |  | //     Debug.LogWarningFormat(" |-- {0}", m_FreeList[i].name); | 
|---|
|  |  |  | 
|---|
|  |  |  | if (IsEmpty()) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | m_Prefab = null; | 
|---|
|  |  |  | #if UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS | 
|---|
|  |  |  | Destroy(m_DebugContainer.gameObject); | 
|---|
|  |  |  | #endif | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!string.IsNullOrEmpty(assetBundleName) && !string.IsNullOrEmpty(assetName)) | 
|---|