using BaseGames.Combat; namespace BaseGames.Player.States { /// /// 地面攻击状态(3 段连击)。 /// 由 PlayerController 实例化,AttackEvent 触发切换。 /// 通过 Animancer 帧事件驱动 HitBox 激活/关闭。 /// public class AttackState : PlayerStateBase { private int _comboIndex; public AttackState(PlayerController owner) : base(owner) { } public override void OnStateEnter() { _comboIndex = 0; PlayAttackClip(); Input.AttackEvent += OnAttackInput; } public override void OnStateExit() { Input.AttackEvent -= OnAttackInput; Owner.Combat?.DisableAllWeaponHitBoxes(); } public override void OnStateUpdate() { } public override void OnStateFixedUpdate() { } // ── 内部 ────────────────────────────────────────────────────────────── private void PlayAttackClip() { // ⚠️ 字段名 GroundAttacks(非 AttackChainClips) var clip = AnimCfg.GroundAttacks[_comboIndex]; var state = Anim.Play(clip); var events = state.Events(this); events.OnEnd = OnClipEnd; // HitBox 由 Animancer 归一化时间事件驱动 events.Add(0.3f, () => Owner.Combat?.EnableWeaponHitBox(AttackDirection.Ground)); events.Add(0.6f, () => Owner.Combat?.DisableAllWeaponHitBoxes()); } private void OnClipEnd() { Input.AttackEvent -= OnAttackInput; Owner.Combat?.DisableAllWeaponHitBoxes(); Owner.TryTransitionState(Owner.IdleState); } private void OnAttackInput() { if (_comboIndex < 2) { _comboIndex++; PlayAttackClip(); } } } }