Files
zeling_v2/Assets/_Game/Scripts/Player/States/JumpState.cs
Joywayer 2a6a0b1861 feat: 实现抓墙高度记忆、背墙跳/对墙跳、蹬墙后自动抓墙
- 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>
2026-05-19 12:12:24 +08:00

104 lines
4.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
}