多久更新一次有关世界的游戏客户端?


10

使用socket.io,我的通讯与其他MMORPG相似,与消息保持稳定连接。

到目前为止,在我的设计中,客户端随每个更新帧发送播放器的位置和动画帧。服务器收到该消息后,会将其广播给所有客户端,然后客户端将相应地移动图形。

例如,每1/10秒一次“收集”并广播它们是一个更好的主意吗?

另外,客户是否应该在出现后立即发送许多不同的消息(获得的经验值,单击的项目),或者仅收集一条消息?第一个将更容易实现。

Answers:


16

我将通过高层讨论来解决这个问题,然后解决您的问题。为了公开起见,我没有个人使用socket.io的经验,但是有很多关于MMORPG的问题空间。

MMORPG引擎网络架构的设计和/或选择提供功能的中间件或开源项目是受团队的游戏设计,预算和技术专长影响的更具挑战性的决定之一。最终选择将影响其他体系结构决策(有时还会影响设计决策)。

作为MMORPG的开发人员,我们计划取得巨大成功(通常也称为灾难性成功),在这种情况下,大量的警告灯和警报器会触发。出现的可怕的大量数字之一是N平方的算法(此后为N ^ 2),在您的问题中,我首先想到的是,听起来像是设计要求实体将信息广播到所有其他关联实体。这是N ^ 2问题的经典示例。

MMO通常通过以几种不同的方式攻击N ^ 2问题来解决该问题。意识系统(情境,空间等),其中一个实体了解所有其他实体的某些子集,将玩家划分为不同的“碎片”,将玩家划分为“区域”和/或实例化,实施阻止太多游戏的游戏机制玩家聚集在一起(Asheron Call的传送风暴)等

大多数MMORPG和许多FPS引擎都具有相当复杂的网络体系结构,支持各种功能,包括:

  • 可靠和不可靠的通信路径(TCP,可靠的UDP和UDP数据包的自定义实现)
  • 带宽整形(优先级,生存期等)
  • 自动复制现场/可变数据和函数调用
  • 原子数据集(即一起通信的数据)
  • 离散更新(即每个过渡都很重要的地方)
  • 潜伏期校正
  • 各种技巧使客户感到响应

我发现虚幻网络文档Valve网络文档为各种问题提供了很好的入门。

因此,现在让我们解决问题。

例如,每1/10秒一次“收集”并广播它们是一个更好的主意吗?

很难在这里提供简单的是或否答案...因为它取决于规模(观察实体的数量),更新的频率和更新的大小。例如,如果更新的大小可能会在某个地方占用缓冲区,则将它们全部收集可能是非常错误的。

MMORPG和FPS游戏的客户端通常经过设计,即使它们没有收到比“正常”更多的更新帧的更新,它们也将可视化“看起来”正确的内容。当使用不可靠的通信(UDP)时,您可能会期望在虚空中丢失一些更新,客户端可以通过发送比可靠传输更频繁的更新来弥补这一点。

从对socket.io文档的粗略回顾来看,它似乎同时支持可靠和不可靠的(在术语上是易变的)通信路径。

我首先要解决,需要多久更新一次...

如果播放器以恒定的速率直线移动,则较低的更新频率就可以了,因为观察者可以准确地预测播放器在任何时间点的位置。当玩家转弯或快速改变方向时,则需要更频繁的更新。相反,当玩家根本不移动时,根本没有理由发出移动更新。

无论如何,可能(通常)没有必要将每个帧的更新从客户端发送到服务器。服务器本身可以选择在拥有消息的每个帧中发送消息,或延迟消息(请参阅带宽整形,优先级划分和更新生存期)。

其他类型的更新具有不同的特征...例如,当玩家或生物受到损坏时,将修改“健康”字段。一种实现此方法的方法是在发生更改时立即广播每个更改,但是如果在一个帧或连续的帧中多次更改该值,则会浪费处理和带宽(实现带宽整形的网络体系结构通过将更新合并为当它们具有可用带宽时,仅将最新消息发送给观察客户端。

客户应该在出现后立即发送许多不同的消息(获得的经验值,单击的项目)还是仅收集一条消息?

同样,这里没有简单的是或否答案。取决于您所说的收集的确切含义……两者在不同情况下可能都是正确的,并且还取决于网络层的实现。

相反,为特定实体收集一条消息作为一条消息来发送消息(取决于实现)可以反过来减少发送消息的带宽开销(降低成本)(取决于实现,例如通过字符串传达的字段/值映射)可以增加带宽要求与较简单的特定消息类型相比。

回顾socket.io文档,在我看来,消息开销在频谱的高端,这将有利于收集更新以聚合消息的形式发送,而不是大量的单个更新。

我建议您查看所有您打算复制的更新,例如,大多数MMORPG和FPS都不会费心将玩家点击X事件发送给观察客户端,除非这也会导致他们也意识到其对象的状态更改。


3
+1好答案。我还建议从那里开始简单并优化。垃圾邮件肯定会泛滥成灾,看到您的带宽开始减少。这就是为什么进行压力测试很好的原因。您实现了最幼稚的方法并进行了一些测试;您做了一些优化;您再次进行压力测试,进一步优化,冲洗,然后重复。如果在第一天实施优化绝对不容易,那就继续吧;但请注意,即使是最琐碎的优化也可能带有一些假设,这些假设以后可能会在生产环境中被证实。
工程师

5

这是一个真实示例:RuneScape每隔约0.6秒“滴答”一次。你可以在这里阅读。我想象它从他们的角度简化了事情,因为在他们的脚本中,他们可能以滴答声而不是毫秒来指定计时和延迟。当然,滴答声速率如此之大/很慢,与其他玩家相比,连接速度较慢的用户并不会处于很大的劣势。


0

一种工作方式是将实际数据更改与这些更改的广播分离。当对象发生更改时,请进行修改并设置一个“脏”标志,当需要广播任何更改时,仅发送已标记对象的数据并清除该标志。多次更改的值将在此处自动合并,因为您的更新仅在广播时发送状态。您还可以标记子对象或单个属性,以便仅广播已更改的内容。

哦,通常您不会将动画帧发送到服务器或其他客户端。精确的动画状态通常被视为演示文稿的详细信息,并留给每个客户端来解决,而您只需要确保每个客户端都知道当前正在播放哪个动画即可。


我不会吗 关于姿势或其他东西,我需要确保所有客户都看得到一样吗?
兰博

确保每个客户端看到的都是完全相同的东西是不切实际的,因为信息需要花费时间,不同的客户端具有不同的网络延迟,它们以不同的速度渲染,等等。因此,尝试让每个人同时显示完全相同的帧通常是徒劳的努力。相反,您可能只是尝试确保它们在大约相同的时间开始相同的动画,这已经足够了。
Kylotan
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.