using System; using System.Collections.Generic; using Cielonos.MainGame.Characters; using Lean.Pool; using Sirenix.OdinInspector; using SLSUtilities.LeanPoolAssistance; using UnityEngine; namespace Cielonos.MainGame { public class VFXObject : PooledObject { [NonSerialized] public CharacterBase creator; // 保留既有 Prefab 配置:true 表示默认继承 creator 完整时间,false 表示默认使用 GlobalTime。 public bool affectedByCreatorTimeScale = true; public CreatorTimePolicy TimePolicy => runtimeTimePolicy ?? GetDefaultTimePolicy(); public float DeltaTime => creator?.selfTimeSm?.GetDeltaTime(TimePolicy) ?? Time.deltaTime; public float TimeScale => creator?.selfTimeSm?.GetTimeScale(TimePolicy) ?? 1f; public List particles = new List(); [Tooltip("需要特殊标记的部分")] public Dictionary parts = new Dictionary(); [NonSerialized] private CreatorTimePolicy? runtimeTimePolicy; [NonSerialized] private bool hasCachedTimeComponents; [NonSerialized] private List baseParticleSimulationSpeeds; [NonSerialized] private List animators; [NonSerialized] private List baseAnimatorSpeeds; [NonSerialized] private bool _isWaitingToDespawn = false; public static GameObject Spawn(GameObject vfxPrefab, CharacterBase creator, Transform parent = null, CreatorTimePolicy? timePolicy = null) { VFXObject vfxObject = LeanPool.Spawn(vfxPrefab, parent).GetComponent(); vfxObject.SetTimeContext(creator, timePolicy); return vfxObject.gameObject; } public static GameObject Spawn(GameObject vfxPrefab, CharacterBase creator, Vector3 position, Quaternion rotation, Transform parent = null, CreatorTimePolicy? timePolicy = null) { VFXObject vfxObject = LeanPool.Spawn(vfxPrefab, position, rotation, parent).GetComponent(); vfxObject.SetTimeContext(creator, timePolicy); return vfxObject.gameObject; } private void Reset() { CollectParticles(); } public override void OnSpawn() { if (spawnExecuted) { return; } creator = null; runtimeTimePolicy = null; base.OnSpawn(); _isWaitingToDespawn = false; CacheTimeComponents(); ApplyTimeScale(); } [Button("Collect Particles")] private void CollectParticles() { particles.Clear(); ParticleSystem[] foundParticles = GetComponentsInChildren(); foreach (var ps in foundParticles) { particles.Add(ps); } } /// /// 停止发射粒子并等待现存粒子全部消散后,再将该特效放入池中。 /// public void StopAndDespawn() { if (particles == null || particles.Count == 0) { LeanPool.Despawn(gameObject); return; } foreach (var ps in particles) { ps.Stop(true, ParticleSystemStopBehavior.StopEmitting); } // 标记为正在等待自动销毁,交由 Update 去检测粒子存活状态 _isWaitingToDespawn = true; } protected override void Update() { if (_isWaitingToDespawn) { bool anyAlive = false; for (int i = 0; i < particles.Count; i++) { if (particles[i] != null && particles[i].IsAlive(true)) { anyAlive = true; break; } } if (!anyAlive) { _isWaitingToDespawn = false; LeanPool.Despawn(gameObject); return; // 提前返回,不再执行后续的时间更新 } } UpdateTimer(DeltaTime); ApplyTimeScale(); } public void SetCreator(CharacterBase character) { creator = character; ApplyTimeScale(); } /// /// 设置本次生成的时间上下文。runtime 策略不会写入 Prefab,也会在对象池复用时自动清除。 /// public void SetTimeContext(CharacterBase character, CreatorTimePolicy? timePolicy = null) { creator = character; runtimeTimePolicy = timePolicy; ApplyTimeScale(); } private CreatorTimePolicy GetDefaultTimePolicy() { return affectedByCreatorTimeScale ? CreatorTimePolicy.CreatorFullTime : CreatorTimePolicy.GlobalTime; } private void CacheTimeComponents() { if (hasCachedTimeComponents) { return; } if (particles == null) { particles = new List(); } if (particles.Count == 0) { particles.AddRange(GetComponentsInChildren(true)); } baseParticleSimulationSpeeds = new List(particles.Count); for (int i = 0; i < particles.Count; i++) { baseParticleSimulationSpeeds.Add(particles[i].main.simulationSpeed); } animators = new List(GetComponentsInChildren(true)); baseAnimatorSpeeds = new List(animators.Count); for (int i = 0; i < animators.Count; i++) { baseAnimatorSpeeds.Add(animators[i].speed); } hasCachedTimeComponents = true; } private void ApplyTimeScale() { CacheTimeComponents(); float timeScale = TimeScale; for (int i = 0; i < particles.Count; i++) { if (particles[i] != null) { ParticleSystem.MainModule main = particles[i].main; main.simulationSpeed = baseParticleSimulationSpeeds[i] * timeScale; } } for (int i = 0; i < animators.Count; i++) { if (animators[i] != null) { animators[i].speed = baseAnimatorSpeeds[i] * timeScale; } } } } }