Files
zeling_v2/Assets/_Game/Scripts/Player/States/WallSlideState.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

95 lines
3.1 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>
/// 抓墙状态(架构 05_PlayerModule §2
/// 进入条件:空中贴墙时,按下朝向墙壁的方向键(或蹬墙跳后的自动抓墙)。
/// 高度限制:若当前 Y > wallGrabY首次抓该墙的高度强制下滑且不可蹬墙跳
/// 若当前 Y ≤ wallGrabY静止悬挂可蹬墙跳。
/// 释放条件:主动按下反方向键或落地。
/// </summary>
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<FallState>());
return;
}
// 着地 → 闲置
if (Move.IsGrounded)
{
Owner.TransitionTo(Owner.GetState<IdleState>());
return;
}
// 主动按下反方向键 → 松开墙壁下落
float moveX = Input.MoveInput.x;
if (Mathf.Abs(moveX) > 0.01f && (int)Mathf.Sign(moveX) == -_wallDir)
{
Owner.TransitionTo(Owner.GetState<FallState>());
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<WallJumpState>());
}
}
}