多人游戏开发编年史:第1部分

本系列文章讲述了两个朋友决定用JavaScript编写多人游戏的故事:一个自上而下的太空射击游戏spaaace 。 令人惊讶的是,即使他们完成了,他们仍然继续成为朋友。 这不是一件容易的事,也没有创造游戏。 您可以在这里玩游戏。 物理和网络代码被拆分成一个单独的名为Lance.gg的开源项目。

如果您分叉,我也不会生气。 该代码在此处可用。

JavaScript? 你疯了吗?

关于该主题的文献已经很多,但是从JavaScript的角度来看文献较少,这就是我写这篇文章的原因。 另外,自从编写了现有文献以来,广域网的某些假定特征已经改变。 例如,网络ping时间非常短,甚至接近光速。 从客户端到服务器遍历世界不到一半,只需不到200毫秒即可完成,而光则只需66毫秒。 带宽也比以前高得多。 所有这些都应转化为更好的游戏体验。

JavaScript并不是编写多人游戏的立即显而易见的选择。 不是由一个长镜头。 然而,有许多因素促使它成为可行的选择,其中包括网络速度的提高,高级图形库(如three.js和PixiJS)的可用性-它们利用了canvas和WebGL等技术。 我们对该项目最大的担忧是浏览器中缺少UDP数据包传输-我们担心这会影响网络往返时间。

太空飞船互相射击

我们着手制作的游戏是规范的,基本的太空射击游戏。 想想小行星/恒星控制。 我们称其为spaaace。 这是一个很好的起点,因为它使我们可以尝试运动控制,物理,实时响应,同时创建一款有趣的游戏。

在我们的版本中,每个玩家都在二维环绕世界中驾驶太空飞船。 飞船可以加速,减速,向左或向右转,并向其他飞船发射导弹。

游戏故事的发展

在这些帖子中,我无法现实地描述整个游戏。 但我可以描述这些编年史 :我们在此过程中面临的问题以及如何解决这些问题。 我们使用了哪些工具,以及如何在每次挑战中取得进展。 在我看来,制作游戏的过程本身就很有趣。 编写多人游戏感觉如何? 我们在哪些地区花费最多的时间?

在开发多人游戏的过程中反复出现一个主题。 重复出现的部分是有人玩游戏,而船只(或导弹)开始以奇怪或令人不安的方式来回走动。 我称其为“ poltergeist”,例如:“嗨,加里,当我发射大量导弹时,游戏就变成了poltergeist 。”这相当于去找机械师,说汽车正在发出奇怪的声音。 或去看医生说肚子疼。 它基本上没有告诉我们任何东西。 症状描述是无用的,因此分析总是需要我们查看服务器和客户端的痕迹并慢慢找出问题。

我们的游戏架构依赖于一种称为客户端预测的技术。 此技术要求每个客户端尝试预测中央游戏服务器上当前正在发生的情况,并在从服务器收到新更新时根据需要进行更正。

由于这种技术,每个调查过程都遵循相同的基本模式,从而将问题缩小到特定的子空间。 该问题在服务器上可见吗? 如果不是,是否及时,合理地向客户报告了职位和状态? 如果客户端禁用了预测功能,游戏是否可以正常运行(如果运行不顺利)? 如果客户的预测获得了良好的价值,那么渲染过程中是否会有问题?

挑战1:弯曲。

症状:“船在我转弯时抵抗并拉动”

弯曲是非常缓慢地调整客户端位置以匹配服务器位置的过程。 这个想法很容易理解,但是实际的弯曲配置却不是。 在很多场合,需要调整弯曲结构。

我学到的是:

弯曲必须增量进行,以便每个游戏步骤都应用所需弯曲增量的某个增量。

我们将弯曲定义如下: 在下一次服务器更新到达时,客户端应对服务器的真实值应用的百分比校正 。 但是弯曲不只是一个神奇的数字,就像63%。 弯曲是大量的微调参数。 您需要为位置,速度和旋转的调整指定不同的弯曲系数。 对于游戏中的不同对象类型,所有这些因素将具有不同的值。 所有这些对象的所有这些因素将具有不同的值,具体取决于对象是由播放器直接控制(也就是由玩家拥有),还是仅当新数据从服务器到达时(即远程)才更改对象的位置。

在我们的游戏中,尽管用户按下了旋转按钮,但用户自己的太空飞船有时仍会“抵抗”。 事实证明,这是由于用户自己的太空飞船弯曲所致。 最初,我减少了“用户拥有的对象”的弯曲度,希望它不会与服务器位置大相径庭。 我无法完全关闭它,因为随着时间的流逝,客户端和服务器的位置确实有所不同。 这是因为物理不是确定性的。

但是,令人惊讶的是,玩家拥有的飞船的角度 是确定性的 ,因为它总是按固定的量(顺时针或逆时针)旋转,因此,方位角是游戏步数的直接函数。按下左箭头的位置减去减去按下右箭头的游戏步数。

因此,通过完全关闭角度上的弯曲(仅针对用户拥有的对象)而不是位置弯曲,可以得到所需的平滑行为。 那不是很好吗? 我为您省去了看这本书的麻烦:

挑战2:碰撞检测。

症状:“我用导弹击中了飞船,但飞船没有被杀死”

一方面,我们意识到客户端和服务器不同意杀戮。 一艘船与他人的导弹相撞,就会造成死亡。 我们知道这个问题即将到来,因为我们已经在文献中对此进行了阅读。 我们看到的结果是“误报”,即客户端预测服务器认为是未命中的杀死事件。 这是一个严重的问题。

解决方案非常简单。 我在服务器上设置了比客户端更多(更大)的碰撞半径检查。

这是用于冲突检测的简单实现的摘要。 真正的游戏将使用更高级的算法,例如四叉树或空间哈希。

在本文中,我们仅涵盖了两个挑战。 还有很多–我将在本系列的第2部分中介绍。 要阅读第2部分,请点击此链接。