using System; using System.Collections.Generic; using UnityEngine; using Sirenix.OdinInspector; using SLSUtilities.Feedback; using Cielonos.MainGame.Characters; using Lean.Pool; namespace Cielonos.MainGame.Effects.Feedback { /// /// 特效生成反馈动作,在 Feedback 轨道上生成指定的 VFX 特效。 /// 自动根据执行者的 VFXData 配置进行位置偏移、绑定关系处理。 /// [Serializable] [FeedbackActionColor(0.8f, 0.4f, 0.7f)] public class SpawnVfxAction : FeedbackActionBase { public override string DisplayName => "Spawn VFX"; [Required] [Tooltip("特效的 Key 名称,需在角色的 VFXData 配置文件中注册")] public string vfxName; [LabelText("被打断时停止")] [Tooltip("如果为 true,当反馈轨道被打断(如受击、格挡)时,此特效粒子会被立即回收/停止播放。")] public bool stopOnInterrupt = true; // 运行时状态记录,使用 Dictionary 保证并发/多角色播放时的实例安全 private readonly Dictionary _spawnedVFX = new Dictionary(); public override void OnStart(FeedbackContext context) { if (string.IsNullOrEmpty(vfxName) || context.owner == null) return; CharacterBase character = context.owner.GetComponent(); if (character != null && character.vfxData != null) { GameObject vfxInstance = character.vfxData.SpawnVFX(vfxName, character, context.owner); if (vfxInstance != null) { _spawnedVFX[context.player] = vfxInstance; } } } public override void OnInterrupt(FeedbackContext context) { if (stopOnInterrupt) { if (_spawnedVFX.TryGetValue(context.player, out GameObject vfxInstance)) { if (vfxInstance != null) { LeanPool.Despawn(vfxInstance); } } } Cleanup(context); } public override void OnEnd(FeedbackContext context) { Cleanup(context); } private void Cleanup(FeedbackContext context) { _spawnedVFX.Remove(context.player); } public override bool Validate(out string error) { if (string.IsNullOrEmpty(vfxName)) { error = "VFX Name is not assigned."; return false; } error = null; return true; } } }