具有连接路径的过程二维地图算法


26

要解决的问题:为所有房间相连的基于图块的游戏生成随机的2D地牢地图。

我正在寻找比目前更好的解决方案。

我当前的解决方案是运行两种算法。第一个生成带有其房间的地牢。第二个要确保所有房间都已连接。我很好奇还有什么其他解决方案。更快和/或更容易等。速度并不是真正的问题,但是如果可以免费获得速度,那将是一件好事。更重要的是,我和其他阅读者可以学习不同的方法来解决问题。

以下是我当前的实现。房间目前没有出口,也没有任何2、3或4个方向的出口。

生成地下城房间

设置:将当前房间设置为左上方的房间。

  1. 获取该房间的有效房间类型(其中有效的房间类型是在地牢中没有出口,并且其出口与上方房间和左侧房间的出口相匹配的类型。只需要在上方和上方进行检查即可)由于下面的第2步而离开)。
  2. 放下房间,将x坐标前进一个步骤。如果x坐标超出地牢宽度,则将x坐标设置为0,并将y坐标前进一个步骤。如果y坐标超过地牢高度,则完成。
  3. 从#1开始重复。

然后,我检查是否所有房间都已连接。如果还没有全部连接,我运行第二种算法,该算法以非性感但在地下城布局方面肯定足够好的方式穿过这些房间并进行更改,以便所有被连接起来。

检查是否所有房间都连通

设置:创建一个表示路径的整数2D映射,并将条目初始化为“未处理”(尚未遍历)值-1。将跟踪当前路径的起始路径索引整数设置为1。通过将当前房间添加到要检查的房间堆栈中,将当前房间设置为左上房间。

  1. 如果堆栈中包含要检查的房间,则将其弹出以将房间的路径索引设置为当前路径索引。如果堆栈中不包含任何房间,请增加路径索引并尝试逐列逐行前进以获取房间,直到获得尚未处理的房间。如果找不到房间,我们就完成了。
  2. 检查房间是否在左侧有出口。如果已添加左侧空间,则将其添加到堆栈中。
  3. 对向下,向右和向上方向重复步骤2(因为我们使用的是堆栈,这意味着从顶部方向开始以顺时针顺序遍历房间)。
  4. 从步骤1开始重复。
  5. 如果路径索引计数大于1,则表示房间已断开连接。

如果存在断开连接的房间,则将房间按其路径索引分组,获取最大路径的索引,然后将所有其他房间连接到这些房间。这是一项正在进行中的工作,但是我的(当前的,“粗俗的”)计划是要遍历一个房间组(第一个房间除外)中的每个房间,以检查是否有通往Biggeset房间组的水平或垂直路径,并且如果是这样,请通过在其间注入/更新房间来在其中创建水平/垂直路径。冲洗并重复。丑陋的,是的,但是就视觉模式而言,这是不明显的,因此可以在这种意义上发挥作用。


1
您是否在PCG Wiki上签出过“地牢生成”?它能回答您的问题吗?
congusbongus

@congusbongus肯定有用的阅读。该页面上链接的Donjon生成器很棒。谢谢。
user1323245 2014年

Answers:


33

我所见过的最好,使用最多的算法之一就是使用Binary Space Partitioning生成地下城。

我读过的最好的一般性解释是在《多瑞编年史》(末尾附有备份)中找到的解释,这是因为无需输入代码即可解释该过程,因此将实现留给读者。

可以在以下位置找到有关同一主题的其他两个教程,其中包含代码


建立BSP树

我们从一个充满壁细胞的矩形地牢开始。我们将递归拆分此地牢,直到每个子地牢都具有一个房间大小。地下城分裂使用以下操作:

  • 选择一个随机方向:水平或垂直分割
  • 选择一个随机位置(x表示垂直,y表示水平)
  • 将地牢分为两个子地牢

在此处输入图片说明

现在,我们有两个子地下城A和B。我们可以对两个子城应用相同的操作。

在此处输入图片说明

选择拆分位置时,我们必须注意不要太靠近地牢边界。我们必须能够在每个生成的子地下城中放置一个房间。我们重复直到最低的子地下城具有我们要生成的房间的大小。

在此处输入图片说明

建造地牢

现在,我们在树的每个叶子中创建一个大小随机的房间。当然,房间必须包含在相应的子地下城中。感谢BSP树,我们不能有两个重叠的房间。

在此处输入图片说明

为了建造走廊,我们在树上的所有叶子之间循环,将每片叶子连接到它的姐妹。如果两个房间都有面对面的墙,我们可以使用笔直的走廊。否则,我们必须使用Z形走廊。

在此处输入图片说明

现在,我们在树中找到一个级别,并对父子区域重复该过程。现在,我们可以通过两个房间之间或一个走廊与一个房间或两个走廊之间的链接来连接两个子区域。

在此处输入图片说明

我们重复此过程,直到连接了前两个子地牢A和B

在此处输入图片说明


这项技术永远不会产生循环可能毫无价值,但是我不确定在没有增加更多随机通道的情况下是否有解决办法。还是很好的答案,+ 1
效价

这是一个有希望的开始。只需找出一种添加一些循环的方法,但是我宁愿解决该问题,也不愿继续沿自己目前的道路前进。谢谢。
user1323245 2014年

2
不错!我对ID感兴趣,因此做了一些尝试。在使用随机数时,请务必小心,否则会出现奇怪的结果。而且我想知道是否应该在递归拆分期间不正确处理走廊,因为我看不到在树外构建走廊的简便方法。无论如何,任何有兴趣的小提琴都在这里:jsfiddle.net/gamealchemist/xt57zwb8
GameAlchemist 2014年

虽然我发现在大型环境中可重复的种子过程中存在一些问题。只要您一次生成整个关卡,它可能是我见过的此类最佳方法之一。我为此+1
那个无家可归的人

4

BSP方法显然是用于生成地下城最常用的方法,但它不是唯一的一个。

为了完整起见,我将解释该发电机为我工作。我不得不承认,我不记得在那里我读到这个,所以我只想说,这不是我的发明(一个旧文章了Jamis巴克听起来很熟悉)。

带房间的迷宫

基本思想是,地牢是带有房间的迷宫。因此,此算法的第一步是生成一个迷宫

使用Eller算法的变体生成的迷宫

下一步是使其稀疏(除去死角):

稀疏:清除死角

第三步是添加一些循环(使其不完美),但是我将跳过该图像,因为它几乎不明显(我不需要一个完美的迷宫,所以我在迷宫生成算法上做了一些捷径,所以它已经在这一点上有循环)。

然后,对于步骤4,我们需要删除隔离的单元格:

取出分离的细胞

至此,我们已经完成了走廊,并准备添加房间了。为此,我们执行以下操作:

  1. 生成一组房间(宽度和高度)
  2. 对于每个房间,我们都会遍历所有可能的位置并确定最佳位置。
    • 最佳位置是通过在条件(例如与走廊的邻接)上增加权重来计算的。
  3. 我们放置房间。

到目前为止,我们的地牢将如下所示: 添加房间

最后一步是添加装饰。

绘制门和房间号

最后的想法

  • 我使用了精简版的Eller算法
  • 不同的迷宫算法可能会导致不同的纹理。您可能更喜欢其他算法。例如,下图显示了由于“二叉树”(对角线偏斜)和“递归除法”(长廊)算法的一种变化而产生的不同纹理二叉树与伪递归除法

2
好东西。我一直在寻找不同的方法,因为对不同级别使用不同的算法可以使游戏更加通用。
user1323245 2014年
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.