205 lines
6.7 KiB
C#
205 lines
6.7 KiB
C#
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<ParticleSystem> particles = new List<ParticleSystem>();
|
||
[Tooltip("需要特殊标记的部分")]
|
||
public Dictionary<string, GameObject> parts = new Dictionary<string, GameObject>();
|
||
|
||
[NonSerialized] private CreatorTimePolicy? runtimeTimePolicy;
|
||
[NonSerialized] private bool hasCachedTimeComponents;
|
||
[NonSerialized] private List<float> baseParticleSimulationSpeeds;
|
||
[NonSerialized] private List<Animator> animators;
|
||
[NonSerialized] private List<float> 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>();
|
||
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>();
|
||
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<ParticleSystem>();
|
||
foreach (var ps in foundParticles)
|
||
{
|
||
particles.Add(ps);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止发射粒子并等待现存粒子全部消散后,再将该特效放入池中。
|
||
/// </summary>
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置本次生成的时间上下文。runtime 策略不会写入 Prefab,也会在对象池复用时自动清除。
|
||
/// </summary>
|
||
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<ParticleSystem>();
|
||
}
|
||
|
||
if (particles.Count == 0)
|
||
{
|
||
particles.AddRange(GetComponentsInChildren<ParticleSystem>(true));
|
||
}
|
||
|
||
baseParticleSimulationSpeeds = new List<float>(particles.Count);
|
||
for (int i = 0; i < particles.Count; i++)
|
||
{
|
||
baseParticleSimulationSpeeds.Add(particles[i].main.simulationSpeed);
|
||
}
|
||
|
||
animators = new List<Animator>(GetComponentsInChildren<Animator>(true));
|
||
baseAnimatorSpeeds = new List<float>(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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|