了解多人在线游戏的原理


今天看了篇文章,讲的是多人游戏服务同步的东西。这个问题之前也有疑问,毕竟自己也玩恰鸡,但是没细想。

英文原文:链接

翻译相对还不错的中文译文:链接

挂屡禁不止,肯定有其他绕过这篇文章里技术的方案,仅了解大致原理层面。不做深究。

对于单机游戏而言,客户端和服务器的交互无所谓,只是影响自己。对于多人游戏,就要去考虑用户作弊。

一种方案就是:

image-20221220151817219

不发送状态,而是发送指令,服务端判断处理并返回状态。这样就不会出现人物瞬移开挂的情况了。

但是这样对于网络延迟就太明显了,不可接受。

改进一些就是:假设用户为client1client1发出的指令是正常指令(大部分用户不会开挂),那就在client1发出指令后,上传服务器的同时,在A的电脑上渲染A的指令,比如人物移动。

image-20221220152518617

但是客户端渲染的速度和服务端响应的速度不一定能对上,而且用户往往会连发指令。比如:

image-20221220152615572

client1连发两个移动指令,并且client1的电脑渲染出了移动后的结果,但是过了一段时间后,才收到服务器第一条指令的响应。

一对比,服务器才移动到11位置,怎么本机电脑都移动到12了。

解决:给指令加上序号,客户端本地队列保存发送给服务器的所有指令,收到服务器响应后删除对应的指令。

这样才是一个客户端,多人游戏,多个客户端。

那样client1的动作在其他人看来就是一卡一卡的,因为其他客户端,比如B,是要从服务器接受client1的动作的,但是服务器并不是时刻知道A的状态的(是采样)。

image-20221220153413959

就上这张图中client2看到的client1的两个状态,就要根据插值等方法去模拟连续client1的动作用于client2端的显示了。

这样导致的情况就是client2得到client1的状态是滞后的。可能你躲到了墙后面,以为安全了,下一刻你死了。

因为有延迟,在client1自己看来,自己电脑上已经躲到墙后面了,但是在client2看来,client1躲到围墙后这个状态还没有到服务器,也没有到client2的电脑上,所以client2还是能打到client1的。

如果网络延迟较小,体验应该还行。具体细节不深究了。

各个游戏应该策略不同,可能有异曲同工之妙。怪不得打游戏有时感觉自己已经残血躲起来了,下一刻自己挂了。

Rust实现一下简单的模拟。

搞了半天才跑通。

github代码:链接

示意图,红色是我的操作,绿色是服务器端,蓝色是另一个客户端看到的我的操作。(模拟网络延迟)