Merge branch 'agents/wall-jump-logic-optimization'

# 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
This commit is contained in:
2026-05-19 13:03:04 +08:00
7 changed files with 95 additions and 4 deletions

View File

@@ -76,6 +76,20 @@ namespace BaseGames.Player.States
return; return;
} }
// ── 抓墙:贴墙 + 朝向墙壁按键,或蹬墙跳后的自动抓墙──────────────
var wd = Owner.WallDetector;
if (wd != null && wd.IsTouchingWall)
{
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() public override void OnStateFixedUpdate()

View File

@@ -12,10 +12,11 @@ namespace BaseGames.Player.States
if (AnimCfg?.Idle != null) if (AnimCfg?.Idle != null)
Anim.Play(AnimCfg.Idle); Anim.Play(AnimCfg.Idle);
Move?.ZeroHorizontalVelocity(); Move?.ZeroHorizontalVelocity();
// 落地时重置空中能力计数器 // 落地时重置空中能力计数器及抓墙记录
Owner.ResetAirJumps(); Owner.ResetAirJumps();
Owner.GetState<DashState>()?.ResetAirDash(); Owner.GetState<DashState>()?.ResetAirDash();
Owner.GetState<WallSlideState>()?.ResetWallGrab(); Owner.GetState<WallSlideState>()?.ResetWallGrab();
Owner.SetPostWallJump(false);
} }
public override void OnStateUpdate() public override void OnStateUpdate()

View File

@@ -85,6 +85,20 @@ namespace BaseGames.Player.States
_owner.TransitionTo(_owner.GetState<AirAttackState>()); _owner.TransitionTo(_owner.GetState<AirAttackState>());
return; 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() public override void OnStateFixedUpdate()

View File

@@ -153,6 +153,47 @@ namespace BaseGames.Player.States
? (_movementConfig != null ? _movementConfig.MaxAirJumps : 1) ? (_movementConfig != null ? _movementConfig.MaxAirJumps : 1)
: 0; : 0;
// ── 抓墙高度记忆 API ──────────────────────────────────────────────────
// wallGrabY首次抓住某面墙壁时记录的 Y 坐标;用于防止单面墙无限向上爬。
// wallGrabDir当前记录所属墙壁方向+1=右墙,-1=左墙0=无)。
// isPostWallJump蹬墙跳后未落地标记允许靠近墙壁时自动抓墙。
private float _wallGrabY = float.NegativeInfinity;
private int _wallGrabDir = 0;
private bool _isPostWallJump;
public float WallGrabY => _wallGrabY;
public int WallGrabDir => _wallGrabDir;
public bool IsPostWallJump => _isPostWallJump;
/// <summary>
/// 进入 WallSlideState 时调用。
/// 不同墙壁dir != _wallGrabDir→ 重置并记录新高度;
/// 同一面墙壁 → 保留原记录(防止攀爬重置)。
/// </summary>
public void RecordWallGrab(int dir, float y)
{
if (dir != _wallGrabDir)
{
_wallGrabDir = dir;
_wallGrabY = y;
}
// 同一面墙:保留 _wallGrabY不更新
}
/// <summary>落地时重置抓墙记录(由 IdleState/RunState.OnStateEnter 调用)。</summary>
public void ResetWallGrab()
{
_wallGrabY = float.NegativeInfinity;
_wallGrabDir = 0;
}
/// <summary>
/// 设置蹬墙跳后自动抓墙标记。
/// true由 WallJumpState.OnStateEnter 设置;
/// false由 IdleState/RunState.OnStateEnter落地或 WallSlideState.OnStateEnter已消耗清除。
/// </summary>
public void SetPostWallJump(bool value) => _isPostWallJump = value;
// ── Overlay Layer API供 SpringState / SoulSkill 等叠加动画使用)───── // ── Overlay Layer API供 SpringState / SoulSkill 等叠加动画使用)─────
/// <summary> /// <summary>
/// 在 Overlay LayerLayer 1播放动画叠加于当前 Base Layer 动画之上。 /// 在 Overlay LayerLayer 1播放动画叠加于当前 Base Layer 动画之上。

View File

@@ -11,10 +11,11 @@ namespace BaseGames.Player.States
{ {
if (AnimCfg?.Run != null) if (AnimCfg?.Run != null)
Anim.Play(AnimCfg.Run); Anim.Play(AnimCfg.Run);
// 落地时重置空中能力计数器(绝大多数情况被 IdleState 覆盖,但水平落地直接进入 RunState 时也需要 // 落地时重置空中能力计数器及抓墙记录(水平落地直接进入 RunState 时)
Owner.ResetAirJumps(); Owner.ResetAirJumps();
Owner.GetState<DashState>()?.ResetAirDash(); Owner.GetState<DashState>()?.ResetAirDash();
Owner.GetState<WallSlideState>()?.ResetWallGrab(); Owner.GetState<WallSlideState>()?.ResetWallGrab();
Owner.SetPostWallJump(false);
} }
public override void OnStateUpdate() public override void OnStateUpdate()

View File

@@ -12,6 +12,7 @@ namespace BaseGames.Player.States
/// ///
/// 公共规则: /// 公共规则:
/// 视为第一段跳(不消耗空中跳跃次数);支持可变高度(提前松键截断); /// 视为第一段跳(不消耗空中跳跃次数);支持可变高度(提前松键截断);
/// 蹬墙后标记 PostWallJump允许空中靠近墙壁时自动抓墙
/// 上升结束后转 FallState。 /// 上升结束后转 FallState。
/// </summary> /// </summary>
public class WallJumpState : PlayerStateBase public class WallJumpState : PlayerStateBase
@@ -48,12 +49,17 @@ namespace BaseGames.Player.States
_inputLockTimer = Cfg.WallJumpInputLockDuration; _inputLockTimer = Cfg.WallJumpInputLockDuration;
// 标记蹬墙跳后自动抓墙(在 FallState/JumpState 中消耗)
Owner.SetPostWallJump(true);
// 蹬墙成功后立即恢复空中冲刺次数
Owner.GetState<AerialDashState>()?.ResetAerialDashes();
// 播放蹬墙跳动画:背墙跳/对墙跳使用各自专属 Clip留空时回退到 Jump 动画 // 播放蹬墙跳动画:背墙跳/对墙跳使用各自专属 Clip留空时回退到 Jump 动画
var wallJumpClip = _isAwayJump var wallJumpClip = _isAwayJump
? (AnimCfg?.WallJumpAway ?? AnimCfg?.Jump) ? (AnimCfg?.WallJumpAway ?? AnimCfg?.Jump)
: (AnimCfg?.WallJumpToward ?? AnimCfg?.Jump); : (AnimCfg?.WallJumpToward ?? AnimCfg?.Jump);
if (wallJumpClip != null) Anim?.Play(wallJumpClip); if (wallJumpClip != null) Anim?.Play(wallJumpClip);
Input.JumpCancelledEvent += OnJumpCancelled; Input.JumpCancelledEvent += OnJumpCancelled;
} }
@@ -64,7 +70,18 @@ namespace BaseGames.Player.States
public override void OnStateUpdate() 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) if (!Move.IsRising)
{ {
Owner.TransitionTo(Owner.GetState<FallState>()); Owner.TransitionTo(Owner.GetState<FallState>());

View File

@@ -58,6 +58,9 @@ namespace BaseGames.Player.States
if (AnimCfg?.WallSlide != null) if (AnimCfg?.WallSlide != null)
Anim?.Play(AnimCfg.WallSlide); Anim?.Play(AnimCfg.WallSlide);
// 消耗蹬墙跳后的自动抓墙标记
Owner.SetPostWallJump(false);
Input.JumpStartedEvent += OnJumpPressed; Input.JumpStartedEvent += OnJumpPressed;
} }