# Conflicts: # Assets/_Game/Scripts/Player/PlayerMovement.cs # Assets/_Game/Scripts/Player/States/IdleState.cs # Assets/_Game/Scripts/Player/States/RunState.cs # Assets/_Game/Scripts/Player/States/WallJumpState.cs # Assets/_Game/Scripts/Player/States/WallSlideState.cs
105 lines
4.0 KiB
C#
105 lines
4.0 KiB
C#
using UnityEngine;
|
||
|
||
namespace BaseGames.Player.States
|
||
{
|
||
/// <summary>
|
||
/// 蹬墙跳状态(架构 05_PlayerModule §2,自定义蹬墙跳设计)。
|
||
///
|
||
/// 从 WallSlideState 进入(正常模式下按跳跃键触发)。
|
||
/// 分为两种子类型,由 PrepareEnter 时的水平输入决定:
|
||
/// - 背墙跳(Jump Away):无输入或反方向输入 → 远离墙壁斜上方弹出(WallJumpAwayForce)。
|
||
/// - 对墙跳(Jump Toward):朝向墙壁方向输入 → 沿墙壁方向斜上方弹出(WallJumpTowardForce)。
|
||
///
|
||
/// 公共规则:
|
||
/// 视为第一段跳(不消耗空中跳跃次数);支持可变高度(提前松键截断);
|
||
/// 蹬墙后标记 PostWallJump,允许空中靠近墙壁时自动抓墙;
|
||
/// 上升结束后转 FallState。
|
||
/// </summary>
|
||
public class WallJumpState : PlayerStateBase
|
||
{
|
||
private float _inputLockTimer;
|
||
private int _wallDir;
|
||
private bool _isAwayJump; // true = 背墙跳;false = 对墙跳
|
||
|
||
public WallJumpState(PlayerController owner) : base(owner) { }
|
||
|
||
/// <summary>
|
||
/// 由 WallSlideState 在调用 TransitionTo 之前调用。
|
||
/// wallDir:抓墙方向(+1 右墙 / -1 左墙)。
|
||
/// moveInputX:触发跳跃时的水平输入值。
|
||
/// </summary>
|
||
public void PrepareEnter(int wallDir, float moveInputX)
|
||
{
|
||
_wallDir = wallDir;
|
||
// 无输入或输入方向与墙壁反向 → 背墙跳;输入方向与墙壁同向 → 对墙跳
|
||
int inputDir = moveInputX > 0.1f ? 1 : (moveInputX < -0.1f ? -1 : 0);
|
||
_isAwayJump = (inputDir == 0 || inputDir != _wallDir);
|
||
}
|
||
|
||
public override void OnStateEnter()
|
||
{
|
||
// 施加对应类型的速度
|
||
if (_isAwayJump)
|
||
Move?.WallJumpAway(_wallDir);
|
||
else
|
||
Move?.WallJumpToward(_wallDir);
|
||
|
||
// 蹬墙跳视为第一段跳,重置空中跳跃次数(使二段跳可再次使用)
|
||
Owner.ResetAirJumps();
|
||
|
||
_inputLockTimer = Cfg.WallJumpInputLockDuration;
|
||
|
||
// 标记蹬墙跳后自动抓墙(在 FallState/JumpState 中消耗)
|
||
Owner.SetPostWallJump(true);
|
||
|
||
// 蹬墙成功后立即恢复空中冲刺次数
|
||
Owner.GetState<AerialDashState>()?.ResetAerialDashes();
|
||
|
||
// 播放蹬墙跳动画:背墙跳/对墙跳使用各自专属 Clip,留空时回退到 Jump 动画
|
||
var wallJumpClip = _isAwayJump
|
||
? (AnimCfg?.WallJumpAway ?? AnimCfg?.Jump)
|
||
: (AnimCfg?.WallJumpToward ?? AnimCfg?.Jump);
|
||
if (wallJumpClip != null) Anim?.Play(wallJumpClip);
|
||
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<WallSlideState>());
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 上升结束 → 下落(isPostWallJump 标记保留,FallState 中继续支持自动抓墙)
|
||
if (!Move.IsRising)
|
||
{
|
||
Owner.TransitionTo(Owner.GetState<FallState>());
|
||
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();
|
||
}
|
||
}
|
||
|