- PlayerController: 添加 wallGrabY/wallGrabDir/isPostWallJump 字段及 API - WallSlideState: 高度限制(超限强制下滑不可蹬跳)+ 静止悬挂 + 反向键释放 - WallJumpState: 区分背墙跳(WallJumpAwayForce)/对墙跳(WallJumpBackForce) 蹬墙后标记 PostWallJump 允许空中自动抓墙;恢复空中冲刺次数 - FallState/JumpState: 新增抓墙入口(朝向按键 OR PostWallJump 自动抓墙) - PlayerMovement.WallJump: 增加 jumpAway 参数区分两种跳跃力 - IdleState/RunState: 落地时重置抓墙记录和蹬墙跳标记 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
104 lines
4.0 KiB
C#
104 lines
4.0 KiB
C#
using UnityEngine;
|
||
|
||
namespace BaseGames.Player.States
|
||
{
|
||
/// <summary>
|
||
/// 跳跃状态。
|
||
/// - 一段跳 / 郊狼跳:OnStateEnter 时调用 Move.Jump()。
|
||
/// - 二段跳(二段跳能力解锁后可用):上升或下落途中再按跳跃且 AirJumpsLeft > 0,
|
||
/// 调用 Move.DoubleJump(),重播跳跃动画,不离开本状态(保持速度截断逻辑)。
|
||
/// - 空中冲刺:上升途中按冲刺且 HasAbility(AirDash) → AerialDashState。
|
||
/// - 变高跳:松开跳跃键触发 JumpCancelledEvent → CutJump()(系数 = JumpCutMultiplier)。
|
||
/// - _isDoubleJump:由 FallState 在转换前通过 SetDoubleJump(true) 预设,
|
||
/// 使 OnStateEnter 对二段跳调用 Move.DoubleJump() 而非 Move.Jump()。
|
||
/// </summary>
|
||
public class JumpState : PlayerStateBase
|
||
{
|
||
private bool _isDoubleJump;
|
||
|
||
public JumpState(PlayerController owner) : base(owner) { }
|
||
|
||
/// <summary>
|
||
/// 由 FallState 在转换到 JumpState 前调用,标记本次进入为二段跳,
|
||
/// 以便 OnStateEnter 使用 DoubleJumpForce 而非 JumpForce。
|
||
/// </summary>
|
||
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<FallState>());
|
||
return;
|
||
}
|
||
|
||
// 空中冲刺(优先于二段跳:冲刺可保存二段跳机会)
|
||
if (Buffer.ConsumeDash()
|
||
&& Stats != null && Stats.HasAbility(AbilityType.AirDash))
|
||
{
|
||
var aerialDash = Owner.GetState<AerialDashState>();
|
||
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<WallSlideState>());
|
||
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();
|
||
}
|
||
}
|