【问题标题】:Storing and loading 2d infinite procedurally generated tile based world存储和加载 2d 无限程序生成的基于瓦片的世界
【发布时间】:2018-07-25 13:27:05
【问题描述】:

背景:

我正在研究 2d 无限世界生成。它是基于瓷砖的,这意味着我的地形完全由正方形组成。你可以把它想象成 2d Minecraft(从上方看地形)。

我实现了标准块系统,其中地形被分割成小的 8x8 瓷砖区域,随着玩家在世界各地移动,这些区域会被加载和删除。到目前为止,这可以非常顺利地工作,没有任何打嗝或滞后。我正在使用 Lua 和 Corona SDK。

问题:

由于玩家将能够修改地形,我需要一个快速高效的系统来在玩家加载新区块后将区块保存在内存中,以及从内存中加载这些区块的系统如果它们之前已加载。

这就是问题发生的地方。它需要经常读取和保存到文件(内存),这会导致明显的延迟。使块更大不是一种选择。

我尝试过但都导致延迟的解决方案:

a) 我实施的第一个也是显而易见的解决方案是只为每个块创建一个文本文件,并将图块名称作为字符串。它看起来像这样:x12y10.txt 在文件中,我只是转储了所有磁贴名称,以便它们需要放置在屏幕上:"Grass Grass Water Sand Sand Sand Grass Grass..."。这行得通,但加载字符串很慢,所以我尝试了另一种解决方案:将切片另存为索引。

b) 将图块保存为它们的索引。我将每个图块与一个数字配对。由于数字更短,它们占用的内存更少,加载速度更快。我给了每个图块它自己的索引:Grass -> id 1Water -> id 2Sand -> id 3 等等。这样我只需要保存 1 或 2 个字符而不是每个图块的完整字符串。我的 txt 文件现在看起来像这样:"1 1 2 3 3 3 1 1..."。这效果更好,但仍然导致延迟。

c) 我做的下一个改进是块在内存中的组织方式。我没有将所有块都转储到一个文件夹中,而是为每个 x 坐标创建了一个文件夹并将所有具有该 x 值的块放入其中。

所以不要这样:

  • 包含所有块的文件夹:x0y0.txtx0y1.txtx0y2.txtx1y0.txtx1y1.txtx1y2.txt

包含所有块的文件夹内我有这个:

  • 文件夹 x0:x0y0.txtx0y1.txtx0y2.txt

  • 文件夹 x1:x1y0.txtx1y1.txtx1y2.txt

我不确定这对少量块有多大帮助,但我很确定对于数千块,改进是有的。

可能的解决方案?

我有一些改进的想法,但我想听听您对解决方案的意见。

a) 将地形保存为二进制文件?

b) 我已经阅读了有关 Minecraft 区域格式的信息,我真的很想了解它是如何工作的,但由于关于它的信息很少,所以没有得到它。因此,如果有人知道并可以向我解释他们的系统,我将不胜感激。

c) 另一种更快的文件格式?

d) 制作/访问许多文件夹很慢吗?有更好的选择吗?

【问题讨论】:

  • 为什么要将数据保存在文件中?使用位于内存中的单个 Lua 表:{['x12y10']='1 1 2 3 3 3 1 1', ['x0y0']='2 1 2 1 2 1 2 1', ...}
  • 地形可以无限生成。将表中的每一块都倾倒是一个非常糟糕的主意。如果有变化,地形也需要保存。离开游戏后,该 lua 表将被销毁,地形变化也会随之删除。
  • 人类无法进行如此多的更改以溢出 Lua VM 内存。在一个表中存储一百万个修改过的单元格对于 Lua 来说是可以的。一百万次鼠标点击是人类点击的 11 天 :-) 是的,表格必须在退出时保存并在进入时加载。

标签: memory optimization lua coronasdk procedural-generation


【解决方案1】:

我真的觉得这是 cs-101 问题,但不能马上用谷歌搜索任何答案,所以快速总结。

所有文件都只是字节序列。如果我们谈论的是读取和写入原始字节,那么任何格式都不会让 64 字节出现在内存中的速度比另一种更快。

文本文件是一个字节序列,对它们的值有轻微的限制(嗯,限制是如果你想要标准的文本程序来显示它)。来自文本文件的字符串"11"(位序列:110001110001)不会比“二进制”文件中的不可打印位序列100000100000 更快地加载。

在尝试打开您请求打开的文件时,结构化目录至少可以减少系统检查的节点数量。但是文件系统底层的机制非常复杂,受很多因素的影响。总体猜测是,即使是小文件的频繁读取也会很慢。并且所有文件都有一些存储开销(系统信息以保持跟踪和排序),小文件的有用/辅助信息比率较低。我知道至少有一个带有可变地图的 2d 项目,在几年前它们转移到更大的文件之前,它会让硬盘发出咆哮和咕噜声。

您不必使块更大,这是不同的事情,但您可以将它们写入同一个文件。 您可以拥有一个兆字节的文件(假设每个块使用一个字节),而不是 64 字节的数百万个文件。一百万块对于玩家来说是很多修改或四处走动的。如果您将该数据解压缩到表中,它将占用更多空间,但您不必破译所有字符串,只需破译当前需要的字节。是的,在 lua 中修改一个兆字节的字符串会导致创建另一个很慢的兆字节字符串,但是您不必每次都这样做,或者您可以将字符串拆分为较小的字符串并进行修改。并且只在需要时进行写作。 I/O 缓冲甚至可能在没有您干预的情况下发生,但它通常对大文件很有帮助。 是的,每个图块将有超过一个字节的信息(但是,每个图块有 2^8 个可能的状态很多),系统保持不变。

同样的事情是done 用于纹理,因为在一个大勺中加载一个大块中的数据比到处搜索微小的位更快。索引一个长长的内存区域也比四处寻找指针要快。

除此之外,您可能会尝试在内存中读取/写入比您想要的更少的字节数。例如通过压缩数据。

【讨论】:

    【解决方案2】:

    在我的世界中,块不会被存储,除非它们被访问/修改过,否则它们会被生成。

    这将为您留下一个系统,其中只需要存储已被玩家修改的块,而未修改的区域每次都使用相同的随机种子重新生成。

    创建修改的层次结构...一个块是一个 8x8 块,创建一个 8x8 块的超级块,如果任何 8x8 超级块已被修改,则仅查找文件。

    可能将所有超级块存储在一个文件中,这会限制文件的数量(添加更多文件确实会降低系统速度,并且还会低效地使用系统空间)。

    如果你有空闲的时间空间,也许在播放器附近有一个块缓存,并预先加载正在接近的修改区域。这将限制所需的可见延迟

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-18
      • 1970-01-01
      • 2013-12-24
      • 1970-01-01
      • 2012-07-06
      • 1970-01-01
      • 2021-12-15
      相关资源
      最近更新 更多