288 lines
8.7 KiB
C#
288 lines
8.7 KiB
C#
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<string, Stack<GameObject>> Pools = new Dictionary<string, Stack<GameObject>>();
|
|
private static readonly HashSet<GameObject> PooledObjects = new HashSet<GameObject>();
|
|
|
|
public static IEnumerator coLoadGameObject(string path, Transform parent, Vector3 localPosition, Quaternion localRotation, Action<GameObject> 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<GameObject> 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<PooledResourceMarker>();
|
|
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<GameObject> pool;
|
|
if (!Pools.TryGetValue(key, out pool))
|
|
{
|
|
pool = new Stack<GameObject>();
|
|
Pools.Add(key, pool);
|
|
}
|
|
|
|
pool.Push(instance);
|
|
PooledObjects.Add(instance);
|
|
return true;
|
|
}
|
|
|
|
public static int GetPooledCount(string path)
|
|
{
|
|
Stack<GameObject> pool;
|
|
return Pools.TryGetValue(NormalizePath(path), out pool) ? pool.Count : 0;
|
|
}
|
|
|
|
public static void Clear(string path)
|
|
{
|
|
string key = NormalizePath(path);
|
|
Stack<GameObject> pool;
|
|
if (!Pools.TryGetValue(key, out pool))
|
|
{
|
|
return;
|
|
}
|
|
|
|
DestroyPool(pool);
|
|
Pools.Remove(key);
|
|
}
|
|
|
|
public static void ClearAll()
|
|
{
|
|
foreach (Stack<GameObject> pool in Pools.Values)
|
|
{
|
|
DestroyPool(pool);
|
|
}
|
|
|
|
Pools.Clear();
|
|
PooledObjects.Clear();
|
|
}
|
|
|
|
private static GameObject Pop(string path)
|
|
{
|
|
Stack<GameObject> 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<PooledResourceMarker>();
|
|
if (marker == null)
|
|
{
|
|
marker = instance.AddComponent<PooledResourceMarker>();
|
|
}
|
|
|
|
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<GameObject> pool)
|
|
{
|
|
while (pool.Count > 0)
|
|
{
|
|
GameObject instance = pool.Pop();
|
|
PooledObjects.Remove(instance);
|
|
DestroyUnityObject(instance);
|
|
}
|
|
}
|
|
|
|
private static void StopEffects(GameObject instance)
|
|
{
|
|
ParticleSystem[] particles = instance.GetComponentsInChildren<ParticleSystem>(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<ParticleSystem>(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;
|
|
}
|
|
}
|
|
}
|