修复内容:

PlayerMovement:新增 _facingLocked 字段 + LockFacing(bool) 方法;UpdateFacing() 锁定时直接返回
WallSlideState:OnStateEnter 调用 LockFacing(true) + FlipFacing(_wallDir);OnStateExit 调用 LockFacing(false) 解锁
WallJumpState:OnStateEnter 保险性再调一次 LockFacing(false);WallJumpAway/Toward 同步写入 _inputVelocityX,确保解锁后 UpdateFacing 朝向正确(背墙跳 = 离墙方向,对墙跳 = 朝墙方向)
This commit is contained in:
2026-05-22 10:48:52 +08:00
parent 285ac46e31
commit 68d4c699ae
15 changed files with 235 additions and 418 deletions

View File

@@ -43,6 +43,7 @@ namespace BaseGames.Player
private bool _isWallRight;
private bool _onOneWayPlatform;
private int _facingDirection = 1;
private bool _facingLocked; // 为 true 时 UpdateFacing() 不覆盖朝向
private bool _cancelWindowOpen;
private SurfaceType _currentSurface = SurfaceType.Ground;
private readonly Collider2D[] _groundBuffer = new Collider2D[4];
@@ -213,6 +214,7 @@ namespace BaseGames.Player
// ── 朝向 ──────────────────────────────────────────────────────────────
public void UpdateFacing()
{
if (_facingLocked) return;
// 读取玩家输入速度(不含平台分量),避免平台横向运动驱动朝向翻转。
float vx = _inputVelocityX;
if (Mathf.Abs(vx) < 0.1f) return;
@@ -247,6 +249,13 @@ namespace BaseGames.Player
transform.localScale = new Vector3(dir, 1f, 1f);
}
/// <summary>
/// 锁定/解锁自动朝向UpdateFacing
/// 传入 true 后 UpdateFacing 不再根据输入速度覆盖朝向,
/// 直到传入 false 解锁。适用于抓墙、蹬墙跳等需要手动控制朝向的状态。
/// </summary>
public void LockFacing(bool locked) => _facingLocked = locked;
// ── 取消窗口 ──────────────────────────────────────────────────────────
public void SetCancelWindowOpen(bool open) => _cancelWindowOpen = open;
@@ -318,7 +327,8 @@ namespace BaseGames.Player
/// </summary>
public void WallJumpAway(int wallDir)
{
_rb.velocity = new Vector2(-wallDir * _config.WallJumpAwayForceX, _config.WallJumpAwayForceY);
_inputVelocityX = -wallDir * _config.WallJumpAwayForceX;
_rb.velocity = new Vector2(_inputVelocityX, _config.WallJumpAwayForceY);
_coyoteTimer = 0f;
}
@@ -328,7 +338,8 @@ namespace BaseGames.Player
/// </summary>
public void WallJumpToward(int wallDir)
{
_rb.velocity = new Vector2(wallDir * _config.WallJumpTowardForceX, _config.WallJumpTowardForceY);
_inputVelocityX = wallDir * _config.WallJumpTowardForceX;
_rb.velocity = new Vector2(_inputVelocityX, _config.WallJumpTowardForceY);
_coyoteTimer = 0f;
}

View File

@@ -195,6 +195,18 @@ namespace BaseGames.Player
OnDamaged?.Invoke();
}
/// <summary>
/// 强制即死,无视无敌帧(危险区域、深渊等环境击杀专用)。
/// GodMode 下仍然豁免。
/// </summary>
public void Kill()
{
if (_isGodMode || !IsAlive) return;
CurrentHP = 0;
_onHPChanged?.Raise(CurrentHP);
OnDamaged?.Invoke();
}
public void FullHeal()
{
if (!IsAlive) return;

View File

@@ -38,6 +38,9 @@ namespace BaseGames.Player.States
public override void OnStateEnter()
{
// 蹬墙时解锁自动朝向(由 WallSlideState.OnStateExit 已解锁,这里保险再做一次)
Move?.LockFacing(false);
// 施加对应类型的速度
if (_isAwayJump)
{

View File

@@ -62,6 +62,11 @@ namespace BaseGames.Player.States
_lastGrabDir = _wallDir;
}
// 锁定自动朝向,防止 LateUpdate 的 UpdateFacing 覆盖手动设置的朝向
Move?.LockFacing(true);
// 抓墙时始终面朝墙壁,确保背墙跳的 FlipFacing(-_wallDir) 能正确翻转朝向
Move?.FlipFacing(_wallDir);
// 计算当前是否处于正常模式
UpdateCanJump();
@@ -76,6 +81,7 @@ namespace BaseGames.Player.States
public override void OnStateExit()
{
Move?.LockFacing(false);
Input.JumpStartedEvent -= OnJumpPressed;
}
@@ -98,6 +104,25 @@ namespace BaseGames.Player.States
return;
}
// ── 抓墙攻击:优先于方向键脱离检测,朝离墙方向翻转后进入空中攻击(无土狼时间)──
if (Buffer.ConsumeAttack())
{
Move.FlipFacing(-_wallDir);
Owner.TransitionTo(Owner.GetState<AirAttackState>());
return;
}
// ── 抓墙冲刺:优先于方向键脱离检测,朝离墙方向翻转后冲出(无土狼时间)──────────
var ds = Owner.GetState<DashState>();
if (ds != null && ds.CanDashMidAir
&& Stats != null && Stats.HasAbility(AbilityType.Dash)
&& Buffer.ConsumeDash())
{
Move.FlipFacing(-_wallDir);
Owner.TransitionTo(ds);
return;
}
// 按下方向键 → 启动墙壁土狼时间后主动脱离,自然下落
if (Input.MoveInput.y < -0.5f)
{
@@ -107,7 +132,6 @@ namespace BaseGames.Player.States
}
// 按反方向键 → 启动墙壁土狼时间后脱离
// wall coyote 存在时,离墙后短窗口内仍可触发蹬墙跳,不会误双跳
float mx = Input.MoveInput.x;
if (Mathf.Abs(mx) > 0.1f && (mx > 0f ? 1 : -1) != _wallDir)
{