用最简单的方式讲清客户端预测
多人联机的移动看起来很复杂。其实只有三步:预测、比较、修正。
为什么需要它
没有服务器权威就无法阻止作弊。但如果每个输入都发给服务器再等回复,玩家看到的角色会在按键 80 毫秒之后才动。那没法玩。
解法是:客户端立刻在本地应用移动,同时把输入发给服务器。换句话说,它在预测未来。
三个步骤
预测:客户端立即模拟输入,并把结果连同 tick 编号写入历史缓冲区。
比较:当服务器发来自己的结果时,客户端将其与该 tick 保存的结果比对。
修正:若差值在容差内则不做处理;否则对齐到服务器位置,并重放该 tick 之后收到的所有输入。
实践中的陷阱
模拟必须是确定性的。相同初始状态下的相同输入必须得出相同结果。依赖 Time.deltaTime 的物理步进会破坏这一点 —— 请使用固定 tick。
不要突兀地修正。把细小的差异分摊到几帧上平滑处理,能避免玩家产生被瞬移的感觉。
void OnServerState(ServerState s)
{
_history.DiscardBefore(s.Tick);
if (Vector3.Distance(s.Position, _history[s.Tick].Position) < TOLERANCE)
return; // tahmin dogru, dokunma
transform.position = s.Position; // duzelt
for (int t = s.Tick + 1; t <= _localTick; t++)
Simulate(_history[t].Input); // ve yeniden oyna
}
csharpReconciliation.cs
从哪里开始
先在固定 tick 上构建单人移动并让它确定化,网络层放在之后。
把这个顺序颠倒过来的团队,最后会同时调试移动 bug 和同步 bug。这是经验之谈。