如何在MMO游戏中处理大量拾音器


26

Minecraft之类的游戏或任何带有拾音器的MMO游戏如何处理它们?

假设您每次挖掘地形时都会产生3滴“污垢”。假设每个项目都有每帧计算的旋转动画。如果全世界的取件数量非常高,那么对于给定服务器中的客户端而言,这将是无用的大量帧开销,因为很可能其中许多取件项距离您仅光年。

所以我认为您只需要在接近本地玩家的拾音器上“做东西”,但这仍然意味着我必须检查每一帧是否有其他拾音器项目足够近以至于必须开始动画。

我的实际问题是:其他MMO如何解决此问题?


9
此外,在Minecraft的环境中,一定数量的项目彼此足够接近后(同一区块空间中3+个相同项目),服务器将3个实例替换为包含区块类型的分组实例(minecraft:dirt)和一个count(30),这样当玩家距离收货足够近时,它会尽可能多地增加玩家的库存。如果玩家仅能容纳6件物品,并且地面上有30个筹码,则玩家将拿起6筹码,地面上的筹码减少到24个
。– Zymus

6
@Zymus值得注意的是,中度掉落物品的滴答声性能实际上下降了,因为它们都在不断寻找附近的物品。
user253751 '17

仔细

Answers:


48

只需简单地将世界上那些靠近玩家的部分加载到内存中即可。其他任何东西都被挂在硬盘上。当在两公里外的地方放置一个微小的物体时,玩家将看不到它,也无法与其互动。因此,没有理由对其进行更新或将其发送到GPU进行渲染。对象及其交互范围越小,需要将其加载到播放器周围的范围越小。

关于找出最接近播放器的内容:主要归结为将世界存储在针对空间查找进行了优化的数据结构中。那些很好的候选者是空间哈希多维树


感谢您及时回复。我当时在考虑使用Unity,因为我猜它使用某种空间划分来检查触发器对撞机,因此我将在角色周围创建一个大的圆形对撞机,并且其中的每个项目都将被“动画化”。这是实现答案的一种方法吗?纠正我,如果我错了,加油!
Alakanu

2
@Alakanu如果希望对象在远处可见但仅在靠近播放器时执行某些计算密集型的行为(并且仅绕其y轴旋转某些东西不会很昂贵),则可以使用它。但是,在Unity中实施开放世界游戏时,真正的挑战是在玩家穿越世界时智能地实例化和销毁游戏对象(甚至更好:使用对象池而不是实例化和销毁)。
菲利普

是的,在这种情况下,对象池是强制性的:)好的,非常感谢!
Alakanu '17

3
@Alakanu您可以查看Minecraft的“加载的块”概念,以获取有关此答案如何应用于该游戏的更多信息。
T. Sar-恢复莫妮卡

1
这不仅适用于皮卡。距离播放器太远的任何物体都可以用这种方式处理。有时甚至是靠近播放器的物体。想象一下一个拥有完整内部装饰的房子,但是直到您真正进入房子才需要渲染。
Zibelas

22

您需要管理两个非常不同的事情:

  1. 服务器必须以授权方式管理整个世界。为此,必须与N个客户端(其中N为“大量”)进行通信。

  2. 从原则上讲,客户可以了解整个世界,但是不需要。对于客户而言,足够了解玩家附近的东西。例如,假设一个相当粗略的网格状分区,则仅需要知道玩家的单元格以及玩家周围的26个单元格(如果您具有2D网格,则需要知道8个单元格)。网格越细越好,但是您可以理解。

现在,很多皮卡是什么?您每秒可能要挖掘5件事,这可能是需要在服务器上更新的二十个数字,并且服务器可能必须将这些数字传输给感兴趣区域与您的小区重叠的其他玩家。对于计算机而言,这是非常荒谬的数据量,而计算量却微不足道。当同一单元中有成千上万的玩家时,这可能会成为挑战(那时您的分区过于粗糙)。

服务器不需要知道,也不必关心拾取器的旋转或此类细节。为什么会这样?

客户实际上也不在乎,因为这只是客户可以即时弥补的眼球。

从服务器的角度来看,有必要知道您正在所在节点中的(30、40、50)处进行挖掘,并且它决定生成例如5个类型为3的对象或7个类型为数3。这就是它所关心的,并且它所传达的所有信息。它还将信息包含在发送给某人的数据中,该人随后将其感兴趣的区域移到网格单元上(假设到那时它仍然在那里)。

客户被告知那里产生了三个物体,等等。现在,无论客户显示的是ASCII艺术图,还是现在有一个“ D”,还是显示旋转的污垢,都一样。桩的旋转角度是否不同,还是仅靠近玩家的旋转角度都相同。只是显示器上显示的内容,不会影响其他任何人。

因此,在您只想旋转附近一堆污垢的具体情况下,您可以对所有已知的对象进行范围检查。由于数据集不大,因此即使对所有内容都使用蛮力也可以使用。

您可以(并且应该)根据分区大小,简单修剪掉距离太远的网格单元。

当然,您可以进一步细分您的单元并使用超级智能的工具。如果可以的话,请使用kd-Tree,但不要期望会有很大的收获。您可以使用Manhattan distace修剪东西,也可以将它们分类为自己的小网格……但是为什么呢?

距离检查(实际上是平方距离,但对您来说是相同的)只是两个乘法和一个加法(已针对MUL,MADD优化,因此实际上只有两个操作),然后是分支或有条件的移动。这几乎与一次不修剪整个网格单元的其他操作一样快。事实上,这是东西,你可能连做在GPU上...

看到您将如何针对同一位置进行几百次或最多几千次的距离检查(平方距离可以很好地工作),那么进行此计算就不会有太多麻烦,甚至更多,因为它是一个相当快的缓存-连续内存上的友好迭代,以及有条件的移动,非常便宜。像(伪代码)之类的东西rot = r[i] + 1; r[i] = ((dx*dx+dy*dy) < DIST_SQ) ? rot : r[i];。那是对每帧数百个值的数组的一次迭代。计算机对此并不关心,它是连续的加载和存储,简单的ALU,没有分支,只有几千次迭代。

这个问题(多对一)与服务器上的问题(多对多)不是同一类。真的,客户不是问题。


对不起,我以为很明显,当我开始谈论帧速率时,我是在谈论一个客户。
Alakanu

1
但是客户永远不会成为问题。客户端非常非大规模,而且非常本地化,它需要比服务器得多的知识。理想情况下,客户端知道玩家所在的空间分区节点(无论是网格是什么),以及紧邻的节点,仅此而已。因此,除非一千个玩家紧挨着站着,否则更新很少。通常,您只需要一个或两个对象的增量,以及在朝一个方向移动一半以上节点宽度后,新网格节点的内容即可。其他一切:不是您的问题。
达蒙

1
关键是太聪明可能是一个愚蠢的主意。您的世界已经在空间上进行了划分,每个节点中都有可管理的对象数量。现代CPU(甚至包括GPU)更擅长顺序处理大量SoA数据。他们不喜欢不连贯的分支,他们甚至更不喜欢连贯的内存访问-然而,这正是 “附近唯一的进程”所做的。对于可管理的数字(几百,几千),一个单元内的“全部处理”是完全足够的,并且可能是您可以做的最好的事情。
达蒙

1
@Alakanu对我来说,这似乎是对您的问题的详细而完整的答案。如果您认为这不是答案,则可能是您误解了它,或者您的问题不清楚,以至于Damon,我和所有赞成此答案的人都误解了它。
David Richerby

2
@Alakanu您确实确实花费大量时间向试图帮助您的人抱怨。祝你好运。
David Richerby

2

@ T.Sar在评论中写道,您应该查看Minecrafts的“已加载块”概念以获取更多信息。如果这样做了,请注意,由于人们在游戏中建造机器,因此在Minecraft中这相当复杂。

一个非常简化的版本如下:

世界被划分为正方形区域(块)。在Minecraft中也有一个高度划分,但是大多数mmos不需要。

游戏客户端只关心靠近玩家的区域。这比在播放器周围画一个圆要简单得多,但是非常好。

在Minecraft中,区域为16x16块,客户知道大约9x9区域,每个方向上有4个区域。(东边4个区域+区域球员在+西边4个区域= 9个区域。南北相同)

这些数字没有什么神奇的,可以在游戏中使用任何有意义的东西。

客户只会在该区域内制作动画。服务器仅计算诸如在靠近某个玩家的区域中游荡的怪物之类的事情。

当玩家在一个区域内走动时,没有什么特别的事情发生,当他们越过区域边界时,“动画边缘”被推到一个区域上。然后,客户端需要向服务器询问它现在看到的区域。

有几个嵌套的动画限制没有错。例如,有生命的物品掉落在3x3区域中,怪物在5x5区域中徘徊,而景观仅在9x9区域中显示。

服务器保留没有玩家看到的区域的“冻结版本”。如果这需要大量内存,则可能需要一段时间后将其卸载。当玩家下次到达时,将重新加载区域,而物品不会掉落。下次您需要更快一点,播放器1。


绘制距离是可调的,但是在这种情况下8块是9x9,这是客户端决定的,它可以通知服务器加快速度(因此服务器不会发送客户端不会渲染的数据)。另外...《毁灭战士》和《雷神之锤》没有解决仅渲染有意义的问题吗?
SparK's

关于生成掉落的物品……在Minecraft中,只有附近有玩家时,物品才会“老化”。因此,您可以将删除的项目“保存”到卸载的块中,然后再获取。
SparK's
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.