using UnityEngine;
namespace BaseGames.Player.States
{
///
/// 抓墙状态(架构 05_PlayerModule §2)。
/// 进入条件:空中贴墙时,按下朝向墙壁的方向键(或蹬墙跳后的自动抓墙)。
/// 高度限制:若当前 Y > wallGrabY(首次抓该墙的高度),强制下滑且不可蹬墙跳;
/// 若当前 Y ≤ wallGrabY,静止悬挂,可蹬墙跳。
/// 释放条件:主动按下反方向键或落地。
///
public class WallSlideState : PlayerStateBase
{
private bool _canWallJump;
private int _wallDir;
public WallSlideState(PlayerController owner) : base(owner) { }
public override void OnStateEnter()
{
if (AnimCfg?.WallSlide != null)
Anim?.Play(AnimCfg.WallSlide);
// 记录当前墙壁方向
_wallDir = Owner.WallDetector != null ? Owner.WallDetector.WallDirection : -Owner.FacingDirection;
if (_wallDir == 0) _wallDir = -Owner.FacingDirection;
// 记录首次抓墙高度(不同墙壁才重置)
Owner.RecordWallGrab(_wallDir, Owner.transform.position.y);
// 消耗蹬墙跳后的自动抓墙标记
Owner.SetPostWallJump(false);
Input.JumpStartedEvent += OnJumpPressed;
}
public override void OnStateExit()
{
Input.JumpStartedEvent -= OnJumpPressed;
}
public override void OnStateUpdate()
{
// 离开墙壁 → 下落
if (Owner.WallDetector == null || !Owner.WallDetector.IsTouchingWall)
{
Owner.TransitionTo(Owner.GetState());
return;
}
// 着地 → 闲置
if (Move.IsGrounded)
{
Owner.TransitionTo(Owner.GetState());
return;
}
// 主动按下反方向键 → 松开墙壁下落
float moveX = Input.MoveInput.x;
if (Mathf.Abs(moveX) > 0.01f && (int)Mathf.Sign(moveX) == -_wallDir)
{
Owner.TransitionTo(Owner.GetState());
return;
}
}
public override void OnStateFixedUpdate()
{
// 每帧重新判断是否允许蹬墙跳(随下滑高度动态变化)
float currentY = Owner.transform.position.y;
_canWallJump = currentY <= Owner.WallGrabY + Cfg.WallGrabMaxHeightGain;
if (_canWallJump)
{
// 高度合法:静止悬挂(冻结垂直速度)
var vel = Move.Rb.velocity;
if (vel.y < 0f)
Move.Rb.velocity = new Vector2(vel.x, 0f);
}
else
{
// 高度超限:强制下滑
Move?.ApplyWallSlide();
}
}
private void OnJumpPressed()
{
// 仅高度合法时才允许蹬墙跳
if (_canWallJump)
Owner.TransitionTo(Owner.GetState());
}
}
}