using UnityEngine; namespace BaseGames.Player.States { /// /// 跳跃状态。 /// - 一段跳 / 郊狼跳:OnStateEnter 时调用 Move.Jump()。 /// - 二段跳(二段跳能力解锁后可用):上升或下落途中再按跳跃且 AirJumpsLeft > 0, /// 调用 Move.DoubleJump(),重播跳跃动画,不离开本状态(保持速度截断逻辑)。 /// - 空中冲刺:上升途中按冲刺且 HasAbility(AirDash) → AerialDashState。 /// - 变高跳:松开跳跃键触发 JumpCancelledEvent → CutJump()(系数 = JumpCutMultiplier)。 /// - _isDoubleJump:由 FallState 在转换前通过 SetDoubleJump(true) 预设, /// 使 OnStateEnter 对二段跳调用 Move.DoubleJump() 而非 Move.Jump()。 /// public class JumpState : PlayerStateBase { private bool _isDoubleJump; public JumpState(PlayerController owner) : base(owner) { } /// /// 由 FallState 在转换到 JumpState 前调用,标记本次进入为二段跳, /// 以便 OnStateEnter 使用 DoubleJumpForce 而非 JumpForce。 /// public void SetDoubleJump(bool isDouble) => _isDoubleJump = isDouble; public override void OnStateEnter() { if (AnimCfg?.Jump != null) Anim.Play(AnimCfg.Jump); if (_isDoubleJump) Move.DoubleJump(); else Move.Jump(); _isDoubleJump = false; // 消耗标记 Input.JumpCancelledEvent += OnJumpCancelled; } public override void OnStateUpdate() { // 上升结束时转为下落 if (Move.Rb.velocity.y <= 0f) { _owner.TransitionTo(_owner.GetState()); return; } // 空中冲刺(优先于二段跳:冲刺可保存二段跳机会) if (Buffer.ConsumeDash() && Stats != null && Stats.HasAbility(AbilityType.AirDash)) { var aerialDash = Owner.GetState(); if (aerialDash != null && aerialDash.HasAerialDash) { _owner.TransitionTo(aerialDash); return; } } // 二段跳:上升阶段即可触发(上升途中任意时刻可二段跳) if (Buffer.ConsumeJump() && Owner.AirJumpsLeft > 0) { Owner.UseAirJump(); Move.DoubleJump(); // 留在 JumpState:速度截断(JumpCancelledEvent)和落地检测逻辑继续生效 if (AnimCfg?.Jump != null) Anim?.Play(AnimCfg.Jump); return; } // ── 抓墙:贴墙 + 朝向墙壁按键,或蹬墙跳后的自动抓墙────────────── var wd = Owner.WallDetector; if (wd != null && wd.IsTouchingWall && !Move.IsGrounded) { int wallDir = wd.WallDirection; bool pressingTowardWall = Mathf.Abs(Input.MoveInput.x) > 0.01f && (int)Mathf.Sign(Input.MoveInput.x) == wallDir; if (pressingTowardWall || Owner.IsPostWallJump) { _owner.TransitionTo(_owner.GetState()); return; } } } public override void OnStateFixedUpdate() { // 空中水平移动:有输入时立即覆盖至目标速度;无输入时施加空气阻力保留动量 if (Mathf.Abs(Input.MoveInput.x) > 0.01f) Move.Move(Input.MoveInput.x * Cfg.RunSpeed); else Move.ApplyAirDrag(Cfg.AirDragFactor); } public override void OnStateExit() { Input.JumpCancelledEvent -= OnJumpCancelled; } private void OnJumpCancelled() => Move.CutJump(); } }