优化移动平台与乘客的速度继承逻辑,改用双缓冲方案以提升平滑度和兼容性

This commit is contained in:
2026-05-21 18:59:22 +08:00
parent 247a218182
commit c7c8171b8a
3 changed files with 52 additions and 30 deletions

View File

@@ -31,7 +31,10 @@ namespace BaseGames.Player
// 下一个 FixedUpdate-200先于状态机 -100读取并清零
// 防止状态机用旧输入把速度重新写成非零值。
private bool _pendingHorizontalZero;
private Vector2 _pendingPlatformDelta; // MovingPlatform 推送的本帧位移,在 FixedUpdate 最前端消费
// 移动平台速度双缓冲Platform(-300) 写入 _nextPlayer(-200) 将 _next 换入 _current 并清零 _next
// StateM(-100) 的 Move() 读取 _current确保速度基于 velocity 设置,与 Interpolate 系统兼容。
private Vector2 _platformVelocity; // 本帧消费StateM 通过 Move() 读取)
private Vector2 _nextPlatformVelocity; // Platform(-300) 写入缓冲区
private bool _isWallLeft;
private bool _isWallRight;
private bool _onOneWayPlatform;
@@ -84,12 +87,11 @@ namespace BaseGames.Player
private void FixedUpdate()
{
// 消费移动平台推送的位移(在 velocity 系统之前直接写 position避免冲突
if (_pendingPlatformDelta != Vector2.zero)
{
_rb.position += _pendingPlatformDelta;
_pendingPlatformDelta = Vector2.zero;
}
// 平台速度双缓冲换入Platform(-300) 已将本帧速度写入 _next
// 这里将其换入 _current 供 Move() 叠加,并清零 _next 以备下帧使用。
// 若本帧玩家已离台Platform 不写 _next换入结果为 Vector2.zero自然恢复独立运动。
_platformVelocity = _nextPlatformVelocity;
_nextPlatformVelocity = Vector2.zero;
// 优先处理来自 Update 的强制清零请求(在状态机 OnStateFixedUpdate 之前执行)。
if (_pendingHorizontalZero)
@@ -128,10 +130,11 @@ namespace BaseGames.Player
/// 直接赋予目标水平速度(按键即全速,松键即停,无加速过渡)。
/// 地面状态每帧直接到达全速;空中调用时同样即时,但配合 ApplyAirDrag
/// 在无输入时自然减速,保留跳出时的动量。
/// 若当前站在移动平台上,自动叠加 <c>_platformVelocity.x</c>,保持与平台同步。
/// </summary>
public void Move(float speedX)
{
_rb.velocity = new Vector2(speedX, _rb.velocity.y);
_rb.velocity = new Vector2(speedX + _platformVelocity.x, _rb.velocity.y);
}
/// <summary>
@@ -189,7 +192,9 @@ namespace BaseGames.Player
// ── 朝向 ──────────────────────────────────────────────────────────────
public void UpdateFacing()
{
float vx = _rb.velocity.x;
// 减去平台速度分量,只根据玩家自身输入速度判断朝向;
// 否则站在横向移动平台上静止时会被平台速度驱动朝向翻转。
float vx = _rb.velocity.x - _platformVelocity.x;
if (Mathf.Abs(vx) < 0.1f) return;
int dir = vx > 0f ? 1 : -1;
if (dir == _facingDirection) return;
@@ -231,14 +236,22 @@ namespace BaseGames.Player
// ── IPassengerReceiver ────────────────────────────────────────────────
/// <summary>
/// MovingPlatform.FixedUpdate(-300) 推送本帧平台位移。
/// 在本类 FixedUpdate(-200) 最前端消费,直接写 _rb.position
/// 与 velocity 系统完全隔离,避免 Dynamic Rigidbody 上 MovePosition + velocity 叠加
/// MovingPlatform.FixedUpdate(-300) 推送本帧平台期望位移。
/// 转换为速度delta / fixedDeltaTime写入下帧缓冲区 _next
/// 在本类 FixedUpdate(-200) 换入 _current由 Move() 叠加到水平速度
/// 基于 velocity 的方案与 RigidbodyInterpolation2D.Interpolate 完全兼容,
/// 消除直接写 _rb.position 导致的视觉抖动/速度不一致。
/// </summary>
public void SetPlatformDelta(Vector2 delta) => _pendingPlatformDelta += delta;
public void SetPlatformDelta(Vector2 delta)
=> _nextPlatformVelocity += delta / Time.fixedDeltaTime;
/// <summary>离开移动平台时继承平台速度,防止速度骤变卡顿。</summary>
public void OnLeavePlatform(Vector2 platformVelocity) => _rb.velocity += platformVelocity;
/// <summary>
/// 乘客离开平台时调用。
/// 水平速度已通过 Move() 自然继承(最后一次 Move 调用已包含 platformVelocity.x
/// 此处仅继承垂直分量,保证从竖向移动平台离台时无速度突变。
/// </summary>
public void OnLeavePlatform(Vector2 platformVelocity)
=> _rb.velocity += new Vector2(0f, platformVelocity.y);
// ── 冲刺 ──────────────────────────────────────────────────────────────
/// <summary>