跳跃靠墙高度修复
This commit is contained in:
@@ -49,9 +49,14 @@ namespace BaseGames.Player
|
||||
private bool _wasGrounded;
|
||||
// 跳跃/二段跳期间禁用斜坡吸附,防止把起跳判定成斜坡而立即下压
|
||||
private bool _slopeSnapDisabled;
|
||||
private readonly Collider2D[] _groundBuffer = new Collider2D[4];
|
||||
private int _groundHitCount;
|
||||
private readonly Collider2D[] _groundBuffer = new Collider2D[4];
|
||||
private int _groundHitCount;
|
||||
private readonly ContactPoint2D[] _slopeContactBuffer = new ContactPoint2D[8];
|
||||
private readonly ContactPoint2D[] _wallContactBuffer = new ContactPoint2D[8];
|
||||
// 跳跃上升阶段贴墙时保护 vy:物理摩擦会在碰墙瞬间降低垂直速度,
|
||||
// 通过 OnCollisionEnter/Stay2D 将 vy 恢复到碰撞前的值。
|
||||
private float _savedVy;
|
||||
private bool _preserveVyOnWallContact;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// ── 运行时调试(Inspector 中可见)───────────────────────────────
|
||||
@@ -111,6 +116,10 @@ namespace BaseGames.Player
|
||||
_pendingHorizontalZero = false;
|
||||
}
|
||||
|
||||
// 保存本帧物理步开始前的垂直速度,用于 OnCollisionEnter/Stay2D 中恢复被墙壁
|
||||
// 摩擦力降低的 vy(状态机 -100 比本脚本 -200 晚执行,不会影响此处的读取时机)。
|
||||
_savedVy = _rb.velocity.y;
|
||||
|
||||
CheckGrounded();
|
||||
CheckWalls();
|
||||
|
||||
@@ -283,6 +292,47 @@ namespace BaseGames.Player
|
||||
/// <summary>消耗墙壁土狼时间,防止同一帧被多次触发。</summary>
|
||||
public void ConsumeWallCoyote() => _wallCoyoteTimer = 0f;
|
||||
|
||||
// ── 跳跃上升贴墙 vy 保护 ──────────────────────────────────────────────
|
||||
/// <summary>
|
||||
/// JumpState.OnStateEnter/Exit 调用,开启/关闭跳跃上升阶段的 vy 保护。
|
||||
/// 开启后,OnCollisionEnter/Stay2D 检测到水平墙壁接触且角色有朝墙速度时,
|
||||
/// 将 vy 恢复到本帧物理步前的值,消除物理摩擦对跳跃最高点的影响。
|
||||
/// </summary>
|
||||
public void SetPreserveVyOnWallContact(bool preserve)
|
||||
=> _preserveVyOnWallContact = preserve;
|
||||
|
||||
private void OnCollisionEnter2D(Collision2D collision)
|
||||
=> TryRestoreVyFromWallFriction(collision);
|
||||
|
||||
private void OnCollisionStay2D(Collision2D collision)
|
||||
=> TryRestoreVyFromWallFriction(collision);
|
||||
|
||||
/// <summary>
|
||||
/// 检测水平墙壁碰撞时是否因摩擦力降低了 vy,若是则恢复到碰撞前的值。
|
||||
/// 只在角色确实以朝向墙壁的水平速度(_inputVelocityX)发生碰撞时才恢复,
|
||||
/// 防止 ZeroHVel 正常工作(vx=0,无摩擦)的帧中错误地抵消重力。
|
||||
/// </summary>
|
||||
private void TryRestoreVyFromWallFriction(Collision2D collision)
|
||||
{
|
||||
if (!_preserveVyOnWallContact || _savedVy <= 0f) return;
|
||||
for (int i = 0; i < collision.contactCount; i++)
|
||||
{
|
||||
float nx = collision.GetContact(i).normal.x;
|
||||
if (Mathf.Abs(nx) > 0.5f)
|
||||
{
|
||||
// 法线朝右(nx > 0.5)= 左侧墙,角色朝左运动时产生摩擦(vx < 0)
|
||||
// 法线朝左(nx < -0.5)= 右侧墙,角色朝右运动时产生摩擦(vx > 0)
|
||||
bool hadVelocityIntoWall = (nx > 0.5f && _inputVelocityX < -0.1f)
|
||||
|| (nx < -0.5f && _inputVelocityX > 0.1f);
|
||||
if (hadVelocityIntoWall)
|
||||
{
|
||||
_rb.velocity = new Vector2(_rb.velocity.x, _savedVy);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── IPassengerReceiver ────────────────────────────────────────────────
|
||||
/// <summary>
|
||||
/// MovingPlatform.FixedUpdate(-300) 推送本帧平台期望位移。
|
||||
@@ -445,6 +495,20 @@ namespace BaseGames.Player
|
||||
|
||||
_isWallLeft = Physics2D.Raycast(pos, Vector2.left, len, _groundLayer);
|
||||
_isWallRight = Physics2D.Raycast(pos, Vector2.right, len, _groundLayer);
|
||||
|
||||
// 物理接触点兜底:补充射线未覆盖图层或长度不足时的漏检。
|
||||
// GetContacts 返回上一物理步的接触点,由本脚本(-200)读取时先于状态机(-100),
|
||||
// 可在状态机决定是否施加水平速度之前获得"当帧最新"的墙壁接触信息。
|
||||
if (!_isWallLeft || !_isWallRight)
|
||||
{
|
||||
int cnt = _rb.GetContacts(_wallContactBuffer);
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
float nx = _wallContactBuffer[i].normal.x;
|
||||
if (nx > 0.5f) _isWallLeft = true; // 法线朝右 = 左侧有墙
|
||||
if (nx < -0.5f) _isWallRight = true; // 法线朝左 = 右侧有墙
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
|
||||
Reference in New Issue
Block a user