实时策略游戏联网


16

我正在为我修读的计算机科学课程开发实时策略游戏。它最困难的方面之一似乎是客户端-服务器网络和同步。我已经阅读了这个主题(包括1500个archer),但是我决定采用客户端-服务器方法,而不是其他模型(例如,通过LAN)。

这种实时策略游戏存在一些问题。值得庆幸的是,玩家采取的每项行动都是确定性的。但是,某些事件按计划的时间间隔发生。例如,游戏是由砖块组成的,当玩家拿下一块砖块时,“能量水平”(该砖块上的一个值)在被获取后应该每秒增加一。这是一个非常简短的解释,应该可以证明我的用例。

现在,我正在做瘦客户机,它们只是将数据包发送到服务器并等待响应。但是,有几个问题。

当玩家之间的游戏发展为残局时,每秒通常会有超过50个事件(由于已安排的事件,如前所述,堆积),然后开始显示同步错误。我最大的问题是,即使客户之间的状态偏差很小,也可能意味着客户做出不同的决定,这些决定会滚雪球变成完全独立的游戏。另一个问题(目前还不那么重要)是存在延迟,必须等待几毫秒,甚至是他们采取行动才能看到结果的几秒钟。

我想知道我可以使用什么策略和算法使最终用户更轻松,更快速,更有趣。鉴于每秒发生的事件数量很高,而且每场比赛有几个玩家,因此这特别有趣。

TL; DR以每秒> 50个事件的速度生成RTS,如何同步客户端?


您也许可以实现Eve-online的功能并“放慢时间”,以使一切正常处理。
Ryan Erb 2014年

3
这是Planetary Annihilation的客户/服务器模型的强制链接:forrestthewoods.ghost.io/… 这是替代锁步模型的替代方法,似乎对他们来说效果很好。
DallonF

考虑通过发送所有已采集图块的单个更新而不是每个图块的更新来减少事件数量,或者按照Ilmari的回答,通过分散非玩家动作来减少事件数量。
2014年

Answers:


12

我的目标是每秒同步50个事件,这听起来不现实。这就是为什么要谈论1500弓箭手文章中提到的锁定步骤方法的原因!

一句话:在太慢的网络上在太短的时间内同步太多项目的唯一方法是不在太慢的网络上在太短的时间内同步太多项目,而是在所有客户端上确定性地进行状态转换,而仅同步基本需求(用户输入)。


6

玩家执行的每个动作都是确定性的,但是,某些事件会按计划的间隔发生

我认为这是您的问题;您的游戏应只有一个时间轴(用于影响游戏性的事物)。你说,有些事情生长在X的速度每秒 ; 找出一秒钟内有多少个游戏步骤,并将其转换为每Y个游戏步骤 X的速率。然后,即使游戏可能会变慢,所有内容仍保持确定性。

让游戏独立实时运行还具有其他优势:

  • 您可以通过尽快运行来进行基准测试
  • 您可以通过放慢游戏速度进行调试,以查看转瞬即逝的事件,并且如上所述
  • 游戏保持确定性,这对于多人游戏非常重要。

您还提到,当事件> 50或最多延迟几秒钟时,就会遇到问题。与1500个弓箭手中描述的方案相比,它的规模要小得多,因此请查看是否可以对游戏进行概要分析并找出速度下降的位置。


1
+1:基于帧是正确的选择,而不是基于时间。您当然可以尝试每秒保持N帧。轻微的故障比完全取消同步更好。
PatrickB 2014年

@PatrickB:我看到许多游戏使用的“模拟”时间与视频帧无关。魔兽世界每100毫秒只会更新一次法力值,矮人要塞默认为每个视频帧10滴答。
Mooing Duck

@Mooing Duck:我的评论是针对RTS的。对于可以容忍并在以后纠正的小错误(例如MMORPG,FPS),使用连续值不仅很好,而且很关键。但是,必须在多台计算机之间同步进行确定性仿真吗?坚持帧。
PatrickB

4

首先,要解决计划事件的问题,请不要在事件发生时进行广播,而应在计划时进行广播。也就是说,与其每秒发送“增加瓦数(xy)的能量”消息,不如发送一条消息“ 每秒增加瓦数(xy)的能量直到充满或直到中断”。然后,每个客户端负责本地调度更新。

实际上,您可以进一步推广此原理,并且仅传输玩家动作:其他所有内容都可以由每个客户端(和服务器,必要时)在本地计算。

(当然,您可能还应该偶尔传输游戏状态的校验和,以检测任何意外的失步,并在发生这种情况时具有某种机制来重新同步客户端,例如,通过将所有游戏数据从服务器的权威副本重新发送到客户端,但这应该是罕见的事件,只有在测试或罕见的故障期间才遇到。)


其次,要使客户端保持同步,请确保您的游戏具有确定性。 其他答案已经为此提供了很好的建议,但让我提供一个简短的摘要:

  • 使您的游戏在内部以回合为基础,每回合或“滴答”花费例如1/50秒。(实际上,您有可能在1/10秒或更长的时间内逃脱。)在单回合中发生的任何玩家动作都应视为同时发生。所有消息,至少是从服务器到客户端的消息,都应标上转弯号,以便每个客户端都知道每个事件发生在哪个转弯。

    由于您的游戏使用的是客户端-服务器架构,因此您可以让服务器充当每个回合期间发生情况的最终仲裁者,从而简化了某些事情。但是要注意,这意味着客户端还必须从服务器重新确认自己操作:如果客户端发送一条消息,说“我将X单元向左移动一个磁贴”,而服务器的回复中没有提到X单元的移动,则客户端必须假设它没有发生,并可能取消他们可能已经开始播放的任何预测性运动动画。

  • 为同一回合中发生的“同时”事件定义一致的顺序,以便每个客户端将以相同的顺序执行它们。该顺序可以是任何顺序,只要它是确定性的,并且对所有客户端(和服务器)都相同即可。

    例如,您可以首先增加所有资源(如果一个区块中的资源增长不能干扰另一个区块中的资源增长,则可以一次完成所有工作),然后按预定顺序移动每个玩家的单位,然后移动NPC单位。为了公平起见,您可能想改变转身之间单位移动的顺序,以使每个玩家都同样先行。只要确定性地完成此操作(例如,根据转数),就可以了。

  • 如果您使用浮点数学运算,请确保在严格的IEEE模式下使用它。这可能会使速度变慢,但这是为客户之间的一致性付出的小代价。还请确保在通信过程中不会发生意外的舍入(例如,客户端将舍入后的值传输到服务器,但仍在内部使用未舍入的值)。如上所述,以防万一,拥有一种协议来检测不同步并从不同步中恢复也是一个好主意。


1
另外,同步RNG以启动,并且只有在服务器告诉您时才从同步的RNG中提取。Starcraft1长期存在一个错误,即在重播期间未保存RNG种子,因此重播会慢慢偏离实际游戏。
o鸭

1
@MooingDuck:好点。实际上,我建议您每转一次传输当前的RNG种子,以便立即检测到RNG不同步。另外,如果您的UI代码需要任何随机性,请不要将其从与游戏逻辑相同的RNG实例中提取。
Ilmari Karonen

3

您应该使游戏逻辑与实时性完全独立,并且实质上使其成为回合制游戏。这样,您就确切地知道“瓷砖能源变化发生了”的转折点。在您的情况下,每转仅需1/50秒。

这样,您只需要担心玩家的输入,其他所有内容都由游戏逻辑来管理,并且在所有客户端上完全相同。即使游戏因网延迟或计算异常复杂而停顿了片刻,每个人的事件仍在同步进行。


1

首先,您必须了解PC浮点/双精度数学不是确定性的,除非您指定严格使用IEEE-754进行计算(这很慢)

然后这就是我要实现的方式:客户端连接到服务器,并增加时间(注意ping延迟!)(长时间玩游戏,可能需要重新同步时间戳/转向)

现在,客户端每次执行操作时,都会包含一个时间戳/转弯,并由服务器决定是否拒绝错误的时间戳/转弯。然后,服务器将动作发送回客户端,并且每次“关闭”转弯(aka服务器将不接受如此古老的转弯/时间戳记)后,服务器会将动作和转弯动作发送给客户端。

客户将拥有2个“世界”:一个与终点转弯同步,另一个是从终点转弯开始计算,将到达队列的动作加起来,直到当前客户转弯/时间戳。

由于服务器会接受一些旧的操作,因此客户端可能会直接在队列中添加自己的操作,因此至少对于您自己的操作,网络上的往返时间将被隐藏。

最后一件事是将更多操作排入队列,以便您可以填充MTU数据包,从而减少协议开销;一个好主意是在服务器上执行此操作,因此每个转弯事件都包含对队列的操作。

我在实时射击游戏上使用了这种算法,并且运行良好(在有和没有客户端执行自己的操作的情况下,但服务器ping低至20 / 50ms),每台X转向服务器也会发送特殊的“客户端映射”数据包,以纠正漂移值。


通常可以这样避免浮点数学问题-在RTS中,通常可以轻松地使用整数/不动点进行仿真和移动,并且仅将浮点用于不影响游戏行为的显示层。
彼得斯2014年

用整数很难做水平瓷砖,除非它是一个八角形板。没有固定的硬件加速,因此它可能比浮动的慢。ieee754
Lesto 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.