using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UObject = UnityEngine.Object; namespace XGame { public static class ResourcePoolManager { private const string MainName = "Main"; private const string PoolRootName = "Cache"; private static readonly Dictionary> Pools = new Dictionary>(); private static readonly HashSet PooledObjects = new HashSet(); public static IEnumerator coLoadGameObject(string path, Transform parent, Vector3 localPosition, Quaternion localRotation, Action action) { GameObject instance = TryGet(path, parent, localPosition, localRotation); if (instance != null) { action?.Invoke(instance); yield break; } UObject loaded = null; yield return XResLoader.coLoadRes(path, typeof(GameObject), obj => loaded = obj); GameObject prefab = loaded as GameObject; if (prefab == null) { action?.Invoke(null); yield break; } instance = UObject.Instantiate(prefab, parent); instance.transform.localPosition = localPosition; instance.transform.localRotation = localRotation; Mark(instance, path); RestartEffects(instance); action?.Invoke(instance); } public static IEnumerator coLoadGameObjectWorld(string path, Vector3 position, Quaternion rotation, Action action) { GameObject instance = TryGetWorld(path, position, rotation); if (instance != null) { action?.Invoke(instance); yield break; } UObject loaded = null; yield return XResLoader.coLoadRes(path, typeof(GameObject), obj => loaded = obj); GameObject prefab = loaded as GameObject; if (prefab == null) { action?.Invoke(null); yield break; } instance = UObject.Instantiate(prefab, position, rotation); Mark(instance, path); RestartEffects(instance); action?.Invoke(instance); } public static GameObject TryGet(string path, Transform parent, Vector3 localPosition, Quaternion localRotation) { GameObject instance = Pop(path); if (instance == null) { return null; } Transform transform = instance.transform; transform.SetParent(parent, false); transform.localPosition = localPosition; transform.localRotation = localRotation; instance.SetActive(true); RestartEffects(instance); return instance; } public static GameObject TryGetWorld(string path, Vector3 position, Quaternion rotation) { GameObject instance = Pop(path); if (instance == null) { return null; } Transform transform = instance.transform; transform.SetParent(null, false); transform.SetPositionAndRotation(position, rotation); instance.SetActive(true); RestartEffects(instance); return instance; } public static bool Release(GameObject instance) { if (instance == null) { return false; } PooledResourceMarker marker = instance.GetComponent(); return marker != null && Release(marker.Path, instance); } public static bool Release(string path, GameObject instance) { if (string.IsNullOrEmpty(path) || instance == null) { return false; } string key = NormalizePath(path); if (PooledObjects.Contains(instance)) { return true; } Mark(instance, key); StopEffects(instance); instance.SetActive(false); instance.transform.SetParent(EnsurePoolRoot(), false); Stack pool; if (!Pools.TryGetValue(key, out pool)) { pool = new Stack(); Pools.Add(key, pool); } pool.Push(instance); PooledObjects.Add(instance); return true; } public static int GetPooledCount(string path) { Stack pool; return Pools.TryGetValue(NormalizePath(path), out pool) ? pool.Count : 0; } public static void Clear(string path) { string key = NormalizePath(path); Stack pool; if (!Pools.TryGetValue(key, out pool)) { return; } DestroyPool(pool); Pools.Remove(key); } public static void ClearAll() { foreach (Stack pool in Pools.Values) { DestroyPool(pool); } Pools.Clear(); PooledObjects.Clear(); } private static GameObject Pop(string path) { Stack pool; string key = NormalizePath(path); if (!Pools.TryGetValue(key, out pool)) { return null; } while (pool.Count > 0) { GameObject instance = pool.Pop(); PooledObjects.Remove(instance); if (instance != null) { Mark(instance, key); return instance; } } Pools.Remove(key); return null; } private static void Mark(GameObject instance, string path) { PooledResourceMarker marker = instance.GetComponent(); if (marker == null) { marker = instance.AddComponent(); } marker.Path = NormalizePath(path); } private static Transform EnsurePoolRoot() { GameObject main = GameObject.Find(MainName); if (main == null) { main = new GameObject(MainName); } Transform poolRoot = main.transform.Find(PoolRootName); if (poolRoot != null) { return poolRoot; } GameObject cacheObject = new GameObject(PoolRootName); Transform cacheTransform = cacheObject.transform; cacheTransform.SetParent(main.transform, false); cacheTransform.localPosition = Vector3.zero; cacheTransform.localRotation = Quaternion.identity; cacheTransform.localScale = Vector3.one; return cacheTransform; } private static void DestroyPool(Stack pool) { while (pool.Count > 0) { GameObject instance = pool.Pop(); PooledObjects.Remove(instance); DestroyUnityObject(instance); } } private static void StopEffects(GameObject instance) { ParticleSystem[] particles = instance.GetComponentsInChildren(true); for (int i = 0; i < particles.Length; i++) { particles[i].Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); } } private static void RestartEffects(GameObject instance) { ParticleSystem[] particles = instance.GetComponentsInChildren(true); for (int i = 0; i < particles.Length; i++) { particles[i].Clear(true); particles[i].Play(true); } } private static string NormalizePath(string path) { return string.IsNullOrEmpty(path) ? string.Empty : path.Replace('\\', '/'); } private static void DestroyUnityObject(UObject obj) { if (obj == null) { return; } if (Application.isPlaying) { UObject.Destroy(obj); } else { UObject.DestroyImmediate(obj); } } private sealed class PooledResourceMarker : MonoBehaviour { public string Path; } } }