Files
Cielonos/Assets/Scripts/MainGame/Effects/VFX/VFXObject.cs
SoulliesOfficial 39b43680a9 爆更
2026-07-18 03:16:20 -04:00

205 lines
6.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}
}
}
}