去年夏天,我认为尝试创建基于浏览器的Minecraft克隆将是一个有趣的练习。 当然已经完成了,但这并没有阻止我投入大量时间。 我决定将其称为“新土壤”。 在这里,我将概述为游戏创建世界存储系统的过程,以及如何从Minecraft借用它。


首先,让我们从基础开始。 典型的Minecraft世界被分解为“块”,这些块只是大型连续块(体素)的集合。 这些在游戏中非常容易使用,因为我们一次只能处理几百个。 但是,我们随机生成的世界会变得相当大,尤其是因为在“新土壤”中,我们可以按照玩家的意愿深入地底或向上的天空。 这意味着一个典型的世界在仅仅一两个小时的探索中就可以变成数百万个大块! 将每个块作为文件保存到磁盘上效率很低,因为文件很小,我们需要一次处理很多块。 您不能只打开一百万个文件而不会遇到重大问题。
解决方案? 好吧,看看我们已经拥有的! 我敢肯定,您现在就可以猜到。 是的,没错:我们只是将一块区域放入更大的“超级块”中,或者按照Minecraft的称为“ 区域” 。 这样,我们可以将块抽象为更大的结构,这些结构只需要磁盘上的几个文件即可存储一个大的世界。 这是完美的,因为我们要不断地对在空间和时间上彼此靠近的许多块进行操作。

现在,对于“新土壤”,我们的块是可以相互堆叠的立方体,因此我们的区域也应该是立方体! 如上所示,区域文件被简单地标记为“ r”代表“区域”,后跟区域的坐标。 这意味着r_0_0_0是起源区域,世界中心。 玩家始终在块[8,8,8]的区域[0,0,0]的中心生成。 一点也不复杂! 现在,这些区域实际上是如何存储块的? 每个块应存储在文件中的什么位置? 考虑这一点很重要,因为我们不会立即生成整个区域。
首先,我们需要知道每个块应该在文件中的什么位置。 与其说按照创建它们的顺序将每个数据块转储到文件中并进行线性搜索,不如确保将属于该区域的每个数据块都放有自己的位置。 为此,我们存储一个固定大小的表,该表告诉我们某个块是否实际上存储在区域文件中。 为了找到表中给定块的条目,我们只是做一些简单的数学运算:
table_index = (x) + (y * width) + (z * width * height)
该公式的作用是给我们基于三维坐标的一维索引。 宽度和高度是指块的大小。 (因为所有块都是多维数据集,所以它们都是一样的,但不必一定是。)这样,每个块在表中都有一个唯一的条目,我们可以参考该条目以确定是否已存储它。 。
不仅可以具有两个状态,还可以存储状态,不存储状态或为空 。 “空”用于生成但无论如何都变成空的块,例如在天空中。 使用这个额外的标签,我们不会通过实际保存空块来浪费空间。 相反,我们在区域文件中将标签设置为空,然后将其保留。 如果播放器将一些块添加到空块,则其状态在文件中更改为要存储 ,并被压缩并附加到区域文件中。
我们遇到的一个难题是,随着将块添加到块中,某些块的存储大小可能会增加。 我们不能真正“增加”它们在文件中的空间,因此我们不得不通过假设压缩存储块将始终小于一定字节数来妥协。 这也是Minecraft储存区块的方式。

这几乎就是这篇文章! 稍后,我可能会写一些关于我在这个小实验游戏中完成其他事情的方式的信息。 致读者:祝您好运!