听起来您想学习树木!
我是认真的,如果您当前正在遍历所有多维数据集的数组,那么您确实应该研究各种空间数据结构。对于这种情况,重新想象多维数据集世界的最佳方法是像树一样。
在我们探讨原因之前,先考虑一下我们的问题。我们正在寻找一种解决方案,以尽可能低的成本获取玩家可能与之碰撞的附近立方体的列表。此列表应尽可能小,但要尽可能精确。
现在确定该区域,我们需要将玩家的坐标空间映射到立方体贴图的坐标空间。也就是说,我们需要将播放器的浮点位置映射到多维数据集多维数组的离散索引(示例符号可能是world[31][31][31]
,即64 * 64 * 64多维数组的正中间)。
我们可以使用相同的离散索引简单地计算周围的块,也许只对附近的多维数据集进行采样,但这仍然需要不断的重新计算,并且不允许放置不离散的任何对象(即,可能无法映射到多维数据集地图)。
理想的情况是一组铲斗,其中包含我们的多维数据集地图特定部分的多维数据集集,并且均等划分,因此我们无需重新计算周围区域,而只需移入或移出这些区域即可。对于任何非平凡的计算,像这样保存我们的数据可以消除所有立方体的迭代,仅消除附近的这些单个集合。
问题是:我们如何实现这一目标?
对于64 * 64 * 64的世界,想象一下它分解为8 * 8 * 8的区域。这意味着在您的世界中,每个轴(X,Y,Z)将有8个区域。这些区域中的每个区域都包含8个多维数据集,可通过此新的简化索引轻松检索它们。
如果您需要对一组附近的多维数据集执行操作,而不是迭代世界中的每个多维数据集,则可以简单地遍历这些区域,将最大迭代次数从原始的64 * 64 * 64(262144)分解为只需520(8 * 8 * 8 + 8)。
现在,从这个区域世界中缩小,并将这些区域放到更大的超级区域中;其中每个超级区域包含2 * 2 * 2个常规区域。由于您的世界当前包含512(8 * 8 * 8)个区域,因此我们可以将8 * 8 * 8 区域划分为64(4 * 4 * 4)个超级区域,方法是将8 个区域除以每个超级区域 2 个区域。从上面应用相同的逻辑,这将使最大迭代次数从512减少到8,从而找到超区;然后最多64个来查找前进区域(最多72个)!您可以看到这已经为您节省了很多迭代(262144:72)。
我确定您现在可以看到树木的实用性。每个区域都是树上的一个分支,每个超级区域都作为前一个分支。您只需遍历树即可找到所需的内容。使用较小的数据集以最小化总体成本。
下图应帮助您形象化该概念。(图片来自Wikipedia:Octrees):
免责声明:
在如上所述的理想设置中,您的体素世界已经以固定大小的多维数组进行了布局,您可以简单地查询玩家位置,然后用O(1)成本索引周围的方块!(请参阅Olhovsky的说明),但是当您开始考虑自己的世界在体素游戏中很少固定大小时,这将变得更加困难。并且您可能需要数据结构能够将整个超级区域从HDD 加载到内存。与固定大小的多维数组不同,树很容易做到这一点,而不会花费太多时间在组合算法上。