2.0 KiB
2.0 KiB
Context
当前 MovementComponent 的 Reconcile() 方法在收到服务器 PlayerState 后:
- 强制 snap 到 server position
- 重放 pending inputs(可能产生位移)
- 用 bounded correction 从重放后位置收敛回 server position
问题:server position 每帧都在变化(服务器在广播),bounded correction 的收敛目标一直在变,导致永远追不上。
Goals / Non-Goals
Goals:
- 将模拟层(服务器权威 truth)和表现层(纯视觉插值)解耦
- 表现层用 Lerp 替代 bounded correction,消除追赶震荡
- 模拟层只输出"目标位置",表现层只管插值
Non-Goals:
- 不改变网络协议或服务器逻辑
- 不修改远程玩家的插值逻辑
Decisions
Decision: 表现层直接设置 rigid.position,不使用 MovePosition
选择:表现层直接设置 _rigid.position
- Rigidbody interpolation 设为
None - 表现层直接写入
_rigid.position和_rigid.rotation - 不经过
Rigidbody.MovePosition(避免物理引擎介入)
Decision: 模拟层收到服务器状态时立即计算 target
收到服务器 PlayerState 时:
- Acknowledge inputs(移除 tick <= AckTick 的输入)
- 从 authoritative position 重放剩余 pending inputs
- 计算
target = authoritativePosition + replayDisplacement - 判断 error:error > SnapThreshold → snap;else → 更新
_presentationTarget
关键:_presentationTarget 在两次收到服务器状态之间保持不变,表现层稳定 Lerp。
Decision: 插值策略使用 Lerp
固定 alpha = 0.15~0.2。后续可根据 RTT 动态调整或改用 SmoothDamp。
Risks / Trade-offs
[Risk] 插值延迟导致本地玩家看到的位置比服务器延迟 → [Mitigation] Lerp 的延迟是固定的(不像 bounded correction 那样持续追赶),且不影响服务器权威性
[Risk] 删除 bounded correction 后无法平滑大误差 → [Mitigation] Snap 阈值(0.5 unit)处理大误差,直接跳到目标;Lerp 处理小误差自然收敛