我知道超级简单的多人游戏设置可能不是一个好主意,但是为什么呢?


11

我正在做一个简单的小MOBA,只是为了好玩。我把所有东西都做成单人游戏,然后我意识到:“糟糕,我应该添加多人游戏,对吧。”

我以前从未进行过联网工作,因此学习如何将Lidgren集成到我的游戏中有趣又很棒。问题是,据我所知,我几乎知道我做事的方式是错误的,因为据我所知,它不足以使主流游戏使用,但是这又有什么问题呢?

基本上,我正在做的是,只要玩家执行某项操作,它就会向服务器发送一条消息,说“嘿,我刚刚做了这件事”。服务器和客户端都运行相同的模拟。然后,服务器向所有其他客户端发送一条消息,告诉他们该家伙做了那个事情。

在大多数情况下,除了在少数情况下,当玩家做某事时,客户会认为它很酷,并自行进行。因此,当您右键单击某个位置以将其移动到该位置时,该玩家的客户便开始将他的家伙移至该位置,然后向服务器发送一条消息以告知其相关信息。

所以基本上:

  • 玩家1发射一个咒语,使他的移动速度提高100%,持续6秒
  • 玩家1的本地客户将该buff添加到他的Unit对象中
  • 玩家1的客户端向服务器发送一条消息,说“嘿,我刚刚施放了此咒语”
  • 服务器确保他确实有足够的魔法来施放该咒语,如果是,则将该buff添加到该Unit对象的服务器副本中
  • 服务器向所有其他客户端发送一条消息,说“嘿,这个家伙刚刚施了这个咒语”
  • 其他所有客户端都会收到此消息,并“很酷”,然后将该buff添加到该玩家的本地Unit对象中

我一直在浏览一些东西,以了解大型游戏是如何进行多人游戏的,这对于刚开始涉足此游戏的人来说有点令人困惑,但是看起来Source引擎发送了一个包含所有更改的数据包。世界每一刻?再说一遍,对于这些东西来说是全新的,但是您真的可以经常推送那么多数据吗?

抱歉,这有点不合理,但是基本上,我想知道为什么我的简单系统不是正确的方法,因为如果是这样,其他游戏会使用它,对吗?


6
您缺少的一个步骤是,服务器还将此消息发送给原始客户端(而不仅仅是其他所有人),以确认或拒绝模拟结果,然后,原始客户端会继续进行下去,或者将自己调整为新的现实。除此之外,此方法还不错,下面的其他答案将帮助您更深入地了解其他方面。
Patrick Hughes

1
令人敬畏的是,我们其他人都有合理的希望,说网络不是那么难。这是可行的。
ashes999

Answers:


12

除了Byte56的答案外,还有几件事情需要考虑:

您将如何在客户端之间就玩家移动进行沟通?与大多数其他玩家的动作(通常是孤立的事件,可能很少出现)不同,移动是连续的。您可以(并且想要)发送和接收更新的速率受到限制。Byte56提到的客户端预测通常涉及有关客户端位置和速度的定期更新。然后,客户端使用Cubic Spline之类的方法在它们之间进行局部插值。

回到前面的第二个问题是UDP无法保证传递。您不能确定您发送的每条消息都会到达,甚至到达正确的顺序。您可以发送数据包1、2和3,服务器会收到3个数据包,然后是1个数据包,而不是2个数据包。通常,它们的顺序正确,并且通常会到达,但并非总是如此。因此,您需要一个对丢失数据包具有鲁棒性的系统。一个简单的确认系统就足够了。通常使用的是一个位域,它告诉另一个节点它是否已收到最后32条消息(对于32位int),以及最后收到的消息是什么。这样,您可以将邮件标记为关键邮件,如果没有收到紧急邮件,则重新发送。 这里有相当不错的讨论

在执行此操作时,您还需要记住,您的客户将彼此之间不同步。在最佳情况下,每个人都将显示其他玩家在前一个网络帧之间进行插值,而您正在处理下一个网络帧。因此,您需要一个(公平地)考虑到玩家执行某个动作时看到的不是该动作时游戏的实际状态的系统。他对旧的,不同步的游戏状态做出了反应。

最后,如果这款游戏旨在提高竞争力,那么您还需要担心作弊。因此,在可能的范围内(并且合理),您必须不信任客户并验证其行为是可能的。“不,你不能穿过那堵墙。不,你不能以比跑步速度还快。不,你不能声称已经击中了那个目标。” 等等

有关更多建议,我建议浏览第二个链接中的其他文章。

祝好运!


6

您所描述的本质上是客户端预测,但是您不会说当服务器和客户端不同意时会发生什么。

它从客户端只是一个哑终端的时代发展而来,将其输入发送到服务器,然后服务器将结果告知客户端。但是,一旦游戏移出局域网(并且经常移出局域网),这种情况下的延迟就很明显。您所描述的是引入了客户端预测来解决此问题。现在,客户端还在等待服务器响应的同时模拟了运动。然后他们就结果达成协议。由服务器授权。

下一步是如何回应分歧。如果您对此没有任何准备,则当客户端和服务器不同意时,您将获得客户端的束缚或远程传送。


5

定时。其他答案未提及服务器和不同客户端上事件的时间安排。根据游戏的不同,这可能需要注意。延迟(又名滞后)在发送数据包和接收数据包之间引入了可变的延迟。时间可能很棘手,但我会尽力解释可能出现的问题。有些游戏可以不用担心,但是这里有一个简单的示例,说明它可能会引起问题。

假设每个人一到达包就对其进行操作。

@ Time 0 (wall time), Player 1 puts up a shield   (Message has been sent, but not received by anyone)
@ Time 1, Player 2 shoots player 1   (Message has been sent, but not received by anyone)

假设时间0(T0)和T1接近。

接下来发生的情况取决于谁在看,以及数据包到达服务器的顺序。服务器应始终拥有最终决定权。如果服务器按照上述顺序接收数据包,则服务器将在击球和选手1(P1)幸存之前应用屏蔽。从P1的角度来看,他自己盖上了盾牌,他会在射击前看到盾牌并幸存。但是P2呢?他们会立即射击,因为他们射击了,但是他们会首先看到盾牌吗?如果为(T0 + latency between P1 and the server + the latency between the server and P2) > T1,则射击后盾牌会升起,P2会认为他们的射击杀死了P1。服务器将必须以某种方式纠正这种情况。

但是,如果服务器以相反的顺序接收数据包(即使T0 <T1也很有可能),则情况相反。P1是错误的(并且失效),而P2是正确的(并且是胜利)。

有几种方法可以处理这种情况,但是最简单的方法是让服务器执行所有操作。您可以尝试在客户端上模拟此操作,但不允许执行任何永久性操作,例如死亡。玩家将不得不等待服务器发出重要的改变游戏规则的确认。

发送带有操作的时间戳可能是有益的。如果您最信任客户,则可以使用这些时间戳来确定首先发生的操作,而不必遵循我们的第一个假设。这可能很棘手,因为从过去接收消息通常意味着您需要能够逆转时间。

时间很有趣吗?无论您最终要做什么,了解这些时间问题都是有帮助的。

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.