84 lines
2.7 KiB
C#
84 lines
2.7 KiB
C#
|
|
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
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 特效生成反馈动作,在 Feedback 轨道上生成指定的 VFX 特效。
|
|||
|
|
/// 自动根据执行者的 VFXData 配置进行位置偏移、绑定关系处理。
|
|||
|
|
/// </summary>
|
|||
|
|
[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<FeedbackPlayer, GameObject> _spawnedVFX = new Dictionary<FeedbackPlayer, GameObject>();
|
|||
|
|
|
|||
|
|
public override void OnStart(FeedbackContext context)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(vfxName) || context.owner == null) return;
|
|||
|
|
|
|||
|
|
CharacterBase character = context.owner.GetComponent<CharacterBase>();
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|