using System;
using Animancer;
using BaseGames.Combat;
using BaseGames.Feedback;
using BaseGames.Parry;
using BaseGames.Player;
using UnityEngine;
namespace BaseGames.Animation
{
///
/// 玩家动画事件接收器(架构 §AnimationModule)。
/// 挂载于玩家 Prefab 根节点。负责将 Animancer 动画时间点回调路由到
/// HitBox 激活、招架窗口、无敌帧、移动取消窗口、反馈等系统。
///
/// 使用方式:
/// 1. 在 Inspector 中填充 _hitBoxes、_hurtBox、_mover、_parrySystem。
/// 2. 将每条 ClipTransition + AnimationEventConfigSO 配对添加到 _bindings。
/// 3. Awake 中 AnimationEventBinder.Bind 自动完成注入。
///
public class PlayerAnimationEvents : MonoBehaviour, IAnimationEventHandler
{
[Serializable]
public struct EventBinding
{
[Tooltip("Animancer ClipTransition(需与动画组件中同一引用绑定)。")]
public ClipTransition clip;
[Tooltip("对应的 AnimationEventConfigSO 资产。")]
public AnimationEventConfigSO config;
}
[Header("子系统引用")]
[SerializeField] private HitBox[] _hitBoxes;
[SerializeField] private HurtBox _hurtBox;
[SerializeField] private PlayerMovement _mover;
[SerializeField] private ParrySystem _parrySystem;
[Header("事件绑定(每个 Clip 对应一个配置资产)")]
[SerializeField] private EventBinding[] _bindings;
private IFeedbackPlayer _feedback;
private void Awake()
{
// IFeedbackPlayer 由父层或同层实现(PlayerFeedback / NullFeedbackPlayer)
_feedback = GetComponentInParent()
?? NullFeedbackPlayer.Instance;
foreach (var b in _bindings)
AnimationEventBinder.Bind(b.clip, b.config, this);
}
// ── IAnimationEventHandler ─────────────────────────────────────────
public void HandleEvent(AnimationEventType type, string payload)
{
switch (type)
{
// ── 命中判定 ──────────────────────────────────────────────
case AnimationEventType.EnableHitBox:
SetHitBoxActive(payload, true);
break;
case AnimationEventType.DisableHitBox:
SetHitBoxActive(payload, false);
break;
case AnimationEventType.AttackImpact:
_feedback.PlayAttackWhoosh();
break;
// ── 招架窗口 ──────────────────────────────────────────────
case AnimationEventType.EnableParryWindow:
_parrySystem?.OpenParryWindow();
break;
case AnimationEventType.DisableParryWindow:
_parrySystem?.CloseParryWindow();
break;
// ── 无敌帧 ────────────────────────────────────────────────
case AnimationEventType.EnableIFrame:
_hurtBox?.SetInvincible(true);
break;
case AnimationEventType.DisableIFrame:
_hurtBox?.SetInvincible(false);
break;
// ── 移动反馈 ──────────────────────────────────────────────
case AnimationEventType.LandImpact:
_feedback.PlayLandImpact();
break;
case AnimationEventType.JumpLaunch:
_feedback.PlayJumpLaunch();
break;
case AnimationEventType.Footstep:
_feedback.PlayFootstep();
break;
// ── 取消窗口 ──────────────────────────────────────────────
case AnimationEventType.CancelWindowOpen:
_mover?.SetCancelWindowOpen(true);
break;
case AnimationEventType.CancelWindowClose:
_mover?.SetCancelWindowOpen(false);
break;
// ── 通用反馈 ──────────────────────────────────────────────
case AnimationEventType.TriggerFeedback:
if (!string.IsNullOrEmpty(payload))
_feedback.TriggerPreset(payload);
break;
case AnimationEventType.PlaySFX:
if (!string.IsNullOrEmpty(payload))
_feedback.PlaySFXById(payload);
break;
}
}
// ── 私有辅助 ───────────────────────────────────────────────────────
///
/// 按 Id 激活或停用 HitBox。
/// payload 为空时操作所有 HitBox;非空时仅操作 Id 匹配的 HitBox。
///
private void SetHitBoxActive(string id, bool active)
{
if (_hitBoxes == null) return;
bool matchAll = string.IsNullOrEmpty(id);
foreach (var hb in _hitBoxes)
{
if (hb == null) continue;
if (matchAll || hb.Id == id)
{
if (active) hb.Activate();
else hb.Deactivate();
}
}
}
}
}