【翻译】快节奏多人游戏同步(第3部分):实体插值

原文链接

简介

在此系列的第一篇文章【原文链接】【他人译文】中,我们介绍了权威服务器的概念以及用它来阻止客户端作弊的有效性。但是,简单使用此技术,极有可能导致出现影响可玩性和响应性的卡顿问题。在第二篇文章中,我们建议用客户端预判来解决这个限制。

这两篇文章介绍的这些概念和技术的最终目的,都是想要即是通过有延迟的互联网连接到权威服务器,也能让单玩家控制的游戏角色能表现地像在单机游戏中一样流畅。

本文将继续探讨将此推广到多玩家连接到同一台服务上的情况。

服务器时间步

在之前的文章中,我们所描述的服务器表现是相当简单的——读取客户端输入,更新游戏状态,然后发给客户端。当多于一个客户端连接时,那么,服务器的主循环多少有些不同。

在这种情况下,多个客户端可能会同时发送输入过来,而且速度非常快(像玩家可以发送指令一样快,如按方向键,移动鼠标或点击屏幕)。在每次收到客户端发来的输入后就更新游戏世界并广播游戏状态会消耗太多的 CPU 和带宽。

好的方法是按收到的顺序将客户端输入放到队列中但不处理。取而代之,以较低的频率更新游戏世界,比如每秒 10 次。每次更新的间隔,在本例中是 100ms,我们称为时间步。在每次更新时循环迭代,应用所有尚未处理的客户端输入(可以用比时间步更小一些的间隔,以使物理模拟更可预测),然后向所有客户端广播新的游戏状态。

总之,游戏世界以可预测的速率独立于客户端输入的存在和数量而更新。

处理低频更新

从客户端的角度来看,这种方法与以前一样平滑——客户端预测独立于更新延迟工作,因此它显然也在可预测的(如果相对不频繁的话)状态更新下工作。 然而,由于游戏状态以低频率广播(如示例,每 100ms),所以客户端只拥有可能在全世界移动的其他实体的非常稀少的信息。

《【翻译】快节奏多人游戏同步(第3部分):实体插值》 客户端 2 所看到的客户端 1

根据你正在开发的游戏类型,有很多方法来处理这个问题。 一般来说,你的游戏实体越可预测,越容易修正。

惯性导航

假设你在制作一个赛车游戏。一辆跑的飞快的车就是可预测的——比如,如果它速度在 100m/s,一秒后它差不多就在开始的位置前面 100m 地方。

为什么是“差不多”?在那一秒中,这辆车可能加速或减速了一点儿,或者向右或左转了一点儿——注意关键字“一点儿”。汽车的机动性特质使得在高速时,其在任何时间点的位置高度依赖于其先前的位置、速度和方向,而不管玩家实际做什么。 换句话说,赛车不能立即做 180º 转弯。

它如何与每 100ms 发送一次更新的服务器一起工作?客户端一开始获得每个比赛的汽车权威的速度和方向。在接下来的 100 ms 它不会收到任何新的信息,但它仍然需要显示它们在奔驰。最简单的做法是假设汽车的方向和加速度将在 100ms 内保持不变,并使用该参数在本地模拟汽车的物理结果。然后,100ms 后,当服务器更新到达时,再修正汽车的位置。

修正相对可大可小,这取决于许多因素。如果玩家将汽车保持在直线上并且不改变汽车速度,则预测位置将与修正后的位置完全相同。另一方面,如果玩家碰撞到某物,则预测的位置将是极其错误的。

注意,惯性导航可应用于低速模拟——例如战舰。事实上,“惯性导航”一词就源于海洋航行。

实体插值

在某些情况下,惯性导航无法用——特别是,在玩家的方向和速度可以立即改变的情况下。例如,在 3D 射击游戏中,玩家通常以非常快的速度跑步、停止和转弯。由于位置和速度不能从先前的数据预测,因此惯性导航基本上是无用的。

当服务器发送权威数据时,您不能只更新玩家位置。那样的话你会在每 100ms 瞬移玩家,游戏就不能玩了。

每 100ms 你只能拿到权威的位置数据。诀窍是如何显示给玩家这期间发生了什么。解决方案的关键是相对于玩家的角色,显示过去的其他玩家角色的状态。

假设您在 t = 1000ms 时接收到位置数据。而您在 t = 900ms 时也收到过数据。所以您知道玩家在 t = 900mst = 1000ms 时的位置。因此,在 t = 1000mst = 1100ms 期间,你给他展示其它玩家从 t = 900mst = 1000ms 期间做了什么。这样你总是显示用户的实际移动数据,只不过晚了 100ms。

《【翻译】快节奏多人游戏同步(第3部分):实体插值》 客户端 2 渲染**过去的**客户端 1 的状态,对已经知道的位置数据进行插值

用于从 t = 900mst = 1000ms 进行插值的位置数据取决于游戏。插值通常工作得很好。如果没有,您可以让服务器在每次更新时发送更详细的运动数据——例如,玩家之后的一段连续的数据,或者每隔 10ms 采样的位置(内插时看起来更好)(您不需要发送10倍的数据——你可以发送增量的小动作,可以针对这种特殊情况优化数据格式)。

注意,使用这种技术,每个玩家看到游戏世界略有不同,因为每个玩家看到的是现在的自己,但其他实体是过去的。然而,即使对于快节奏的游戏,看到的其他实体有 100ms 延迟通常也不会被玩家注意到。

当然有例外——当你需要较高的空间和时间精确度时,如当玩家射击另一个玩家。由于看到的其他玩家是过去的状态,你的目标有 100ms 的延迟——也就是说,你在射击 100ms 前的目标位置!我们将在下一篇文章中讨论这个问题。

总结

在具有权威服务器的客户端-服务器环境中,尽管数据更新稀少还有网络延迟,你仍然要给玩家连续平滑运动的错觉。在系列的第 2 部分中,我们探索了一种方法,使用客户端预测和服务器调和实时显示用户控制的玩家的移动。这确保用户输入对本地角色具有即时效果,消除将使游戏无法正常进行的延迟。

然而,其他实体仍然是一个问题。在这篇文章中,我们探讨了两种处理方式。

一,惯性导航,适用于这些情况下的模拟:实体位置可以从先前的数据(诸如位置、速度和加速度)进行可接受地预估。当这些条件不满足时,这种方法就会失效。

二,实体插值,根本不预测未来的位置——它只使用服务器提供的真实实体数据,因此显示的其他实体在时间上稍有延迟。

最终效果是,玩家看到的是当前自己角色的状态,但看到的其他实体是过去的状态。这通常可以创造一种令人难以置信的无缝体验。

然而,如果不做其他处理,当事件需要高的空间和时间精确度时,例如射击一个移动的目标,就会出问题。客户端 2 渲染的客户端 1 的位置与服务器的不匹配,跟客户端 1 的也不匹配,所以爆头就不可能了!由于没有游戏可以不要爆头效果,我们将在下一篇文章中处理这个问题。

    原文作者:大虾龙行天
    原文地址: https://www.jianshu.com/p/594bb3739187
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞