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

标签 java synchronization udp client-server

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

明显的问题是这些更新在服务器和客户端之间传输需要时间。如果客户端开始攻击敌人,当更新返回到服务器时,服务器很可能已经将游戏状态推进到敌人不再在同一地点并且超出范围的程度。

为了解决这个问题,我一直在努力想出一个好的解决方案。我看过以下内容,它对一些人有所帮助,但并不完全:Mutli Player Game synchronization .我已经得出结论,除了传输游戏的当前状态之外,我还可以传输其他信息,例如方向(或 AI 移动的目标位置)和速度。由此,我有一部分需要在客户端“猜测”实际状态是什么(如服务器所见),方法是将游戏状态推进到 future n 毫秒。

问题是确定状态进展的时间量,因为这将取决于服务器和客户端之间的滞后时间,这可能会有很大差异。另外,我应该将游戏状态推进到客户端查看它时的当前状态(即仅考虑更新到达客户端所花费的时间)还是我应该将其推进到足够远以便发送响应时返回到服务器,到那时它就是正确的状态(考虑往返旅程)。

有什么建议吗?

重申一下:

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

2) 我应该将客户端状态推进到足够远以计入整个往返行程,还是仅计入从服务器到客户端获取数据所需的时间?

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

因为我已经有很多数据包在客户端和服务器之间来回传输,如果必须的话,我不想增加流量。目前,客户端向服务器发送状态更新数据包 (UDP) 约 150 毫秒(仅当某些内容发生变化时),然后服务器接收并处理这些数据包。目前,服务器不对这些数据包发送任何响应。

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

这应该可以让客户端合理地了解他们的滞后情况,而不会产生过多的网络流量。

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

最佳答案

首先,仅供引用,如果您担心少于 1 秒的延迟,您就已经开始脱离 MMO 的现实延迟领域。所有大型 MMO 处理此问题的方式基本上是同时运行两个不同的“游戏”——有一个底层游戏引擎处理所有数学、角色状态、应用数值变化,然后是图形客户端。

第一个“游戏”,即数学和计算,在概念上更接近传统的主机游戏(如旧版 MUD)。考虑来回传递的消息,具有非常高的 ACID 隔离度。这些消息更关心准确性,但您应该假设这些消息可能需要 1-2 秒(或更长时间)来处理和更新。这是确保正确计算生命值等的“规则律师”。

第二个“游戏”是图形客户端。这个客户端真正专注于保持事情发生得比第一个游戏快得多的错觉,同时也将即将到来的事件与图形外观同步。这个图形客户端通常只是简单地弥补了一些不重要的事情。此客户端负责 30 fps+ 图形。这就是为什么很多这些图形客户端使用一些技巧,例如在用户按下按钮时启动攻击动画,但直到第一个游戏解决攻击时才真正解决动画。

我知道这与您的问题的字面解释有点不同,但是一旦您离开网络上并排放置的两台机器,100 毫秒真的很乐观...

关于java - 同步客户端-服务器游戏状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5690899/

相关文章:

java - UDP 数据报 Socket 编程与服务器在 JAVA 和客户端在 C++

c - 未读取的 UDP 数据包会发生什么情况?

Java clone() 方法

java - 带有彩色项目和焦点的彩色 jcombobox

php - 如何将 drupal 事件日历与 Outlook 日历同步

java - AtomicLongMap 读取线程安全

python - UDP 安全和识别传入数据

java - 构造函数使用这个和 super Java

java - 运行springboot应用程序的 "gradle bootRun"和 "gradle run"有什么区别?

c++ - 如何在一个类的不同实例之间共享互斥量?