using UnityEngine; using BaseGames.Combat; namespace BaseGames.Player.States { /// /// 下劈(踩踏 Pogo)状态(架构 05_PlayerModule §2)。 /// 需解锁 AbilityType.DownSlash 才能进入; /// 激活 HitBoxDown,着地或命中后弹跳。 /// public class DownAttackState : PlayerStateBase { private bool _hasHitEnemy; private bool _exited; public DownAttackState(PlayerController owner) : base(owner) { } public override void OnStateEnter() { _hasHitEnemy = false; _exited = false; if (Owner.Combat != null) Owner.Combat.OnDownHitConfirmed += OnDownHitConfirmed; var step = Owner.Weapon?.ActiveWeapon?.GetDirStep(AttackDirection.Down); float spd = Stats?.AnimatorSpeedMultiplier ?? 1f; if (step?.clip?.Clip != null) { var animState = Anim.Play(step.Value.clip); animState.Speed *= spd; var events = animState.Events(this); events.OnEnd = OnClipEnd; var s = step.Value; events.Add(s.hitBoxEnter, () => Owner.Combat?.EnableWeaponHitBox(AttackDirection.Down, s.hitBoxId)); events.Add(step.Value.hitBoxExit, () => Owner.Combat?.DisableAllWeaponHitBoxes()); } else { Owner.Combat?.EnableWeaponHitBox(AttackDirection.Down); OnClipEnd(); } // 下劈为纯向下攻击:保持角色原有的自然下落,不额外施加向下俯冲位移 // (俯冲位移会让下劈手感变成下冲,命中弹跳逻辑见 OnDownHitConfirmed) } public override void OnStateExit() { _exited = true; if (Owner.Combat != null) Owner.Combat.OnDownHitConfirmed -= OnDownHitConfirmed; Owner.Combat?.DisableAllWeaponHitBoxes(); } private void OnDownHitConfirmed(BaseGames.Combat.DamageInfo _) { if (_hasHitEnemy) return; _hasHitEnemy = true; // Pogo 弹跳:命中后向上弹起(独立弹跳力,略矮于满跳),同时重置空中能力(等同落地效果) Owner.ResetAirJumps(); Owner.GetState()?.ResetDashCharge(); Move.PogoBounce(); } public override void OnStateUpdate() { // 着地时回到 Idle / Run if (Move.IsGrounded) { Owner.TransitionTo(Owner.GetState()); } } public override void OnStateFixedUpdate() { // 下劈期间保留完整空中水平操控(与 FallState 同款贴墙保护,防止压墙摩擦/卡角) if (Mathf.Abs(Input.MoveInput.x) > 0.01f) { int inputDir = Input.MoveInput.x > 0 ? 1 : -1; var wd = Owner.WallDetector; bool currentFrameWall = inputDir > 0 ? Move.IsWallRight : Move.IsWallLeft; if (currentFrameWall || (wd != null && (wd.IsTouchingWall && wd.WallDirection == inputDir || wd.HasPartialContact(inputDir)))) Move.ZeroHorizontalVelocity(); else Move.Move(Input.MoveInput.x * Cfg.RunSpeed); } else Move.ZeroHorizontalVelocity(); } private void OnClipEnd() { if (_exited) return; if (!Move.IsGrounded) Owner.TransitionTo(Owner.GetState()); else Owner.TransitionTo(Owner.GetState()); } } }