using UnityEngine; namespace BaseGames.Player.States { /// /// 蹬墙跳状态(架构 05_PlayerModule §2)。 /// 从 WallSlideState 进入;根据输入方向区分背墙跳与对墙跳; /// 蹬墙后标记 PostWallJump,允许空中靠近墙壁时自动抓墙(无需方向键); /// 输入锁结束后如贴墙则自动进入 WallSlideState;否则上升结束后转为 FallState。 /// public class WallJumpState : PlayerStateBase { private float _inputLockTimer; private int _wallDir; private bool _jumpAway; // true = 背墙跳,false = 对墙跳 public WallJumpState(PlayerController owner) : base(owner) { } public override void OnStateEnter() { // 记录墙壁方向 _wallDir = Owner.WallDetector != null ? Owner.WallDetector.WallDirection : 0; if (_wallDir == 0) _wallDir = -Owner.FacingDirection; // 根据输入方向判断跳跃类型: // 无输入或背离墙壁方向 → 背墙跳 // 朝向墙壁方向 → 对墙跳 float moveX = Input.MoveInput.x; bool pressingTowardWall = Mathf.Abs(moveX) > 0.01f && (int)Mathf.Sign(moveX) == _wallDir; _jumpAway = !pressingTowardWall; // 施加蹬墙跳速度 Move?.WallJump(_wallDir, _jumpAway); // 锁定水平输入,防止立即覆盖跳跃速度 _inputLockTimer = Cfg.WallJumpInputLockDuration; // 标记蹬墙跳后自动抓墙(在 FallState/WallJumpState 中消耗) Owner.SetPostWallJump(true); // 蹬墙成功后立即恢复空中冲刺次数 Owner.GetState()?.ResetAerialDashes(); if (AnimCfg?.Jump != null) Anim?.Play(AnimCfg.Jump); Input.JumpCancelledEvent += OnJumpCancelled; } public override void OnStateExit() { Input.JumpCancelledEvent -= OnJumpCancelled; } public override void OnStateUpdate() { // 输入锁结束后检查是否贴墙:自动抓墙(优先于下落判断) if (_inputLockTimer <= 0f) { var wd = Owner.WallDetector; if (wd != null && wd.IsTouchingWall && !Move.IsGrounded) { Owner.TransitionTo(Owner.GetState()); return; } } // 上升结束 → 下落(isPostWallJump 标记保留,FallState 中继续支持自动抓墙) if (!Move.IsRising) { Owner.TransitionTo(Owner.GetState()); return; } } public override void OnStateFixedUpdate() { _inputLockTimer -= Time.fixedDeltaTime; // 输入锁结束后允许水平控制 if (_inputLockTimer <= 0f && Mathf.Abs(Input.MoveInput.x) > 0.01f) Move?.Move(Input.MoveInput.x * Cfg.RunSpeed); } private void OnJumpCancelled() => Move?.CutJump(); } }