一尘不染

同步客户端-服务器游戏状态

java

我正在制作客户端服务器MMO风格的游戏。到目前为止,我已经建立了框架,以便服务器和客户端相互交互以提供状态更新。服务器维护游戏状态并定期计算下一个状态,然后每隔一段时间(每n毫秒)将其发送给所有客户端。用户可以在客户端查看此新状态并做出反应。然后,将这些操作发送回服务器进行处理,并发送给下一次更新。

明显的问题是这些更新在服务器和客户端之间传播需要花费时间。如果客户端采取行动攻击敌人,则在更新返回到服务器之前,服务器很有可能已将游戏状态推进到足够远的程度,以使敌人不再位于同一地点且不在范围内。

为了解决这个问题,我一直在努力提出一个好的解决方案。我看了看下面的内容,它对某些(但不完全)有所帮助:Mutli
Player游戏同步。我已经得出的结论是,我不仅可以传输游戏的当前状态,还可以传输其他信息,例如方向(或AI运动的目标位置)和速度。由此,在客户端,我拥有了“猜测”所需要的部分内容,即通过将游戏状态前进至未来的毫秒,可以了解实际状态(如服务器所看到的)。

问题是确定状态进展的时间,因为这将取决于服务器和客户端之间的延迟时间,这可能会有很大的不同。另外,我应该将游戏状态提升到客户端查看时的当前状态(即仅考虑更新到达客户端所花费的时间),还是应该进行得足够远,以便在发送响应时返回到服务器,届时它将是正确的状态(用于往返旅程的帐户)。

有什么建议?

重申:

1)计算发送和接收之间的时间量的最佳方法是什么?

2)我是否应该使客户端状态进展得足够远,以至于可以计入整个往返行程,或者仅仅是从服务器获取数据到客户端所花费的时间?

编辑:到目前为止我想出了什么

由于我已经在客户端和服务器之间来回传送了许多数据包,因此,如果需要,我不想添加该流量。当前,客户端将状态更新包(UDP)发送到服务器约150毫秒(仅当发生更改时),然后由服务器接收并处理它们。当前,服务器未发送对这些数据包的响应。

首先,我将让客户尝试估计他们的延迟时间。我会将其默认设置为50到100毫秒。我提议服务器(每个客户端)大约每2秒立即响应这些数据包之一,并在特殊的定时更新数据包中发回数据包索引。如果客户端收到定时数据包,它将使用索引来计算该数据包的发送时间,然后使用数据包之间的时间作为新的延迟时间。

这样可以使客户端合理地保持最新状态,而不会有过多的网络流量。

听起来可以接受,还是有更好的方法?这仍然不能回答第二个问题。


阅读 238

收藏
2020-12-03

共1个答案

一尘不染

2)我是否应该使客户端状态进展得足够远,以至于可以计入整个往返行程,或者仅仅是从服务器获取数据到客户端所花费的时间?

假设服务器在时间T0发送状态,客户端在时间T1看到状态,玩家在时间T2做出反应,服务器在时间T3获得他们的答案,并立即对其进行处理。在此,往返延迟为T1-T0
+ T3-T2。在理想世界中,T0 = T1和T2 =
T3,观察时间与玩家行为处理之间的唯一延迟是玩家的反应时间,即T2-T1。在现实世界中,它是T3-T0。因此,为了模拟理想世界,您需要减去整个往返延迟:

T2-T1 = T3-T0 + (T1-T0 + T3-T2)

这意味着速度较慢的网络上的播放器会比速度较快的网络上的播放器看到更高级的状态。但是,这对他们没有好处,因为要花更长的时间才能处理完他们的反应。当然,如果两个玩家紧挨着并使用不同的速度网络,这可能会很有趣。但这是不可能的情况,不是吗?

整个过程存在一个问题:您在将来进行推断,这可能会导致荒谬的情况。其中有些功能,例如跳入墙壁很容易避免,但取决于玩家互动的功能则无法避免。1个

也许您可以颠倒您的想法:而不是进行预测,而是在T3-(T1-T0 +
T3-T2)时评估玩家的动作。如果您确定将以这种方式命中角色,请相应地降低其命中点。这可能比原始想法更容易,更现实,或者可能更糟,或者根本不适用。只是一个想法。


1想象两个玩家互相对抗。根据推断,它们在右侧彼此通过。实际上,其中一个改变了方向,最后它们在左侧彼此通过。

2020-12-03