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();
}
}