基于树结构的圆形迷宫生成方法

游戏设计中,迷宫是一种常见的元素,它能够为玩家提供探索和解谜的乐趣。然而,传统的迷宫生成算法往往依赖于随机性,这使得生成的迷宫难以保证特定的属性,例如恰好有四个死胡同。为了解决这个问题,本文将介绍一种基于树结构的圆形迷宫生成方法,该方法能够生成具有特定属性的迷宫。

在开始之前,让先了解一些术语:

  • 门(Door):迷宫中的通道,通常用蓝色表示。
  • 障碍(Barrier):迷宫中的墙壁,通常用绿色表示。
  • 死胡同(Dead End):迷宫中的封闭区域,通常用红色表示。
  • 环(Ring Level):迷宫中的层次,通常用数字表示。

主要概念

整个迷宫的创建过程依赖于树结构。树的每一层(i)对应迷宫中的一个环(i),因此迷宫中的环数等于树的高度。树的节点代表特定环中的门,例如,树的根节点是迷宫的入口点:外环中的一个缺口。连接层(i)的节点A到层(i+1)的节点B的边确保了从环(i)到内环(i+1)的直接路径。父节点P的两个子节点A和B(或更多)将导致一个障碍将每个子节点分开;这是因为从A的子树中的节点到B的子树中的任何节点的唯一方式是访问P。迷宫的解决方案将是一条从树的根节点到最低层的节点的路径(深度等于树的高度)。

构建迷宫

现在,主要思想已经就位(树->迷宫),如何根据给定的树实际绘制迷宫呢?需要弄清楚以下几点:

  • 对于每个门,需要确定其在环上的位置。
  • 对于每个层(i)的节点,需要计算其段的尺寸,即:它限制了其内环(i+1)的哪一部分(参见图1)。

规则

计算门的位置和障碍位置(由角度表示)是从内环向外环进行的,使用一条经验法则:当试图决定门的角度时,其左右障碍已经被前一步确定。最深层的节点被特殊处理,因为它们没有障碍。对于这些节点,首先将环分成N段,其中N是树最深层的节点数。然后,通过在其段的边界内随机选择一个角度来确定它们的角度。

扩展树

在向上遍历(从叶子到根)的过程中,可能会遇到某个层的节点没有子节点。这样的节点被认为是死胡同,在这些情况下,将无法确定节点的角度,因为它缺少障碍值。显然,无法继续向上设置其父障碍。

为了解决这个问题,将树扩展成一棵满树:每个层小于树高度的叶子节点都将通过添加额外的节点扩展,直到达到树的高度。每个添加的节点都将被标记为特殊ID,这样就可以在后面的阶段识别并删除这些额外的节点。

绘制迷宫

几乎完成了。在这一点上,实际绘制迷宫相当容易。首先绘制完整的圆圈,每个树的层都有一个。接下来,在圆圈上绘制弧线,创建门,根据之前计算的角度在环内添加障碍。注意,不需要绘制左右两个障碍。一个就足够了,因为一个节点的障碍也是另一个节点的结束障碍。

创建一个树来表示迷宫。扩展树(这就是将如何处理死胡同)。运行实际的计算,将确定门和障碍的角度。将树收缩回其原始结构。根据树节点中存储的信息进行绘制。

局限性

由于算法的性质,生成的迷宫有一些局限性。例如:两个门永远不会导致同一个死胡同。解决迷宫的路径永远不会包含玩家回溯的移动,即从内环到外环。解决方案路径中的所有移动都是从环i到环i+1。

应用

使用树结构来存储关于迷宫/地图的信息可以扩展到跟踪玩家在世界中的位置。可以向世界发送事件,使其根据需要采取行动。例如,当玩家进入任何层“i”的节点时,创建四个怪物攻击玩家,或者在玩家解决当前迷宫时重新生成一个更大的地图。

代码

尽管有开源库实现了图/树数据结构,并提供了处理它们的基本算法(例如BFS),但决定编写自己的实现。主要原因是需要额外的属性来描述树节点。此外,还添加了一些缺少的方法,但大部分只是为了好玩。

意识到代码并不完美(总有改进的余地),但觉得工作处于一个不错的状态。尽量保持代码清晰并添加了注释,所以应该很容易理解其流程,特别是在阅读了上述内容之后。

目前缺少一种方便的方式来创建图形,所以目前代码接受两个输入:深度和扩展,这些用于创建一个节点数等于给定深度的连接图。稍后,该图将使用扩展值进行扩展。另一个想法是将代码导入网络,创建有趣的在线迷宫来解决。

// 示例代码 class Node { constructor(id, depth) { this.id = id; this.depth = depth; this.children = []; } } class Tree { constructor() { this.root = new Node(0, 0); } // 添加子节点 addChildren(parent, children) { for (let child of children) { parent.children.push(new Node(child.id, parent.depth + 1)); } } // 扩展树 extendTree() { // 实现树的扩展逻辑 } // 计算门和障碍的角度 calculateAngles() { // 实现角度计算逻辑 } // 绘制迷宫 drawMaze() { // 实现迷宫绘制逻辑 } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485