【问题标题】:Storing a Minecraft-like map as a JavaScript array将类似 Minecraft 的地图存储为 JavaScript 数组
【发布时间】:2019-12-22 07:41:44
【问题描述】:

我正在编写一个地图编辑器,它将 3D 空间转换为 JavaScript 数组,以便可以将其导出为 JSON 文件。

每个地图都有一个 2D 平面作为地面层(用户必须指定 X 和 Y 大小),然后要添加高度,用户可以在该 2D 平面顶部放置块,遵循 X 和 Y网格(类似于 Minecraft)。

我的想法是为每个 Z 层创建一个数组,并在其中填充有关放置哪些块的信息。因为必须指定地图的 X 和 Y 大小,所以一个简单的数组应该可以解决问题,因为要读取地图,您只需为每个 Z 层数组循环并用其内容填充地图,这将是另一个数组。创建由地面层的 X 和 Y 大小定义的行。

我知道你可以填充像layer[165] = grassBlock 这样的数组 在您声明它们之后,这将使索引 165 之前的所有内容都为空,从而节省空间。但是在 JSON 格式中,该数组在到达该索引之前不会有 164 个零或空值吗?

这甚至是存储 3D 空间的最有效方式吗?我正在尝试尽可能减少地图大小并加快加载时间。

【问题讨论】:

  • 您可以像地图一样存储列。值在 Map 中排序,因此let column = new Map(); column.set(165, 'grass') 意味着上面的所有内容都是无效的。
  • 但是如何将所有这些地图存储到 JSON 文件中?我只是将其转换为数组吗?
  • 是的,这里有一个例子:json = JSON.stringify(Array.from(map.entries())); map = new Map(JSON.parse(json));

标签: javascript arrays performance 3d


【解决方案1】:

如果您只有块/空,那么一个位就足够了,您可以为矩阵使用单个数组 Javascript 类型的数组。

假设矩阵的大小是XYZ,那么坐标(x, y, z)到数组索引的转换可以是:

index = (x*Y + y)*Z + z;

然后可以将映射存储为单个 Uint8Array 对象,初始化长度为 (X*Y*Z + 7) >> 3(每个字节将为您提供 8 位,但您需要四舍五入)。

要读/写一个位,你终于可以使用

bit = (matrix[index >> 3] >> (index & 7)) & 1;  // Read element
matrix[index >> 3] |= 1 << (index & 7);         // Set element to 1
matrix[index >> 3] &= ~(1 << (index & 7));      // Clear element to 0

如果您需要存储一个逻辑 ID 并且不超过 256 个不同的值(包括“空”),那么每个元素一个字节就足够了。 index 的计算如上,但您可以使用 X*Y*Z 的大小,然后使用 matrix[index] 简单地读/写元素。

如果需要多于 256 个但少于 65537 个不同的值,则可以使用 Uint16Array

如果大多数元素除了类之外不携带特定数据(例如,它们只是“空气”、“土地”、“水”)并且只有一小部分需要更多,那么可能是带有“其他”的值,然后只是将(x,y,z) 映射到“其他”块的数据的字典是一种合理的方法(非常简单的代码,仍然可以快速访问和更新)。

请注意,虽然 Javascript 具有有效存储二进制数据的数据类型,但遗憾的是 JSON 不提供通过网络发送/接收任意字节(不是文本)的类型,您需要转换为 base64 编码并从其加载或类似的东西(如果你想使用 JSON)。

【讨论】:

  • 感谢您的详细解答。我很难理解,但要澄清一下,矩阵不会只包含块或空。相反,每个块将是一个与预定义对象相关联的 ID;包含纹理、碰撞和其他属性。
  • @InevitableEntropy:添加了关于存储 ID 的注释。在这种情况下,代码更简单,您可以只使用matrix[index] 而不使用位摆弄代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-17
  • 1970-01-01
  • 1970-01-01
  • 2011-02-28
  • 2020-06-29
  • 2023-01-08
相关资源
最近更新 更多