一个可复现种子的程序化 3D 地牢生成器与探索器,使用 Vite、TypeScript、Three.js 和 Electron 构建。
Labyrinth Loom 会在每次生成时自动创建房间、走廊、门框、墙体、天花板、火把、宝箱、石柱与场景装饰。生成结果完全由种子驱动:相同种子会得到相同的网格、房间、走廊、门、道具位置和几何布局。项目不依赖外部 .glb、.gltf、.fbx、贴图或字体文件。
项目同时提供 Web 版本和 Windows 桌面版本,并暴露结构化数据接口,便于后续接入 AI 生成、自动化测试、地图分析或其它可视化系统。
- 确定性生成:使用 FNV-1a 与 Mulberry32,确保相同字符串种子得到相同布局。
- 完整房间连通性:使用 Prim 最小生成树保证所有房间可达,并额外生成少量环路。
- 正交走廊系统:每个房间由带单次转折的宽走廊连接,适合网格验证与 3D 可视化。
- 多种程序化道具:火把、宝箱、石柱、碎石、蜘蛛网和青苔。
- 纯代码美术:石材纹理、砖缝、污渍、裂纹、尘埃和蛛网均在浏览器中生成。
- 交互式对象检视:点击房间、门框、火把、宝箱、石柱和装饰物可高亮并查看详情。
- 完整中文 UI:玻璃拟态控制台、实时统计面板、自适应布局与移动端压缩布局。
- Web 与桌面双端:Vite 构建静态 Web 应用,Electron 输出 Windows 便携版 EXE。
- 面向自动化:完整结构化数据可通过
window.__DUNGEON__、getDungeonData()与regenerate(seed)访问。
每次点击“刷新未知地牢”都会创建一个新的随机种子,并重新生成:
- 不重叠的矩形房间。
- 房间中心之间的连通图。
- 保证全房间可达的 Prim 最小生成树。
- 增加少量额外连接以形成环路。
- 宽度为 2 格的折线走廊。
- 房间与走廊交界处的门。
- 房间及走廊周围的一格石墙。
- 火把、宝箱、石柱、碎石、蜘蛛网与青苔。
用户可以输入任意文本种子进行复现,例如:
dragon-vault-2026
blue-keep
迷雾矿坑
2026-09-20
生成过程不依赖系统时间或全局随机状态,只依赖种子字符串。相同种子会生成相同的:
- 地图宽高。
- 房间数量、位置和尺寸。
- 走廊路径和连接关系。
- 门的位置与朝向。
- 道具类型、位置、旋转和缩放。
- 地板、墙体和门网格。
- 火把亮度、变体和装饰细节。
generationTimeMs 属于运行时性能遥测,可能因设备不同而变化;自动化比较布局时应忽略该字段。
使用 OrbitControls 提供完整的相机控制:
- 左键拖拽环绕旋转。
- 滚轮缩放。
- 右键拖拽平移。
- 自动旋转模式。
- 可调自动旋转速度。
- 聚焦选中对象或随机房间。
场景中的可交互对象包括:
| 对象 | 可查看信息 |
|---|---|
| 石室 | 编号、尺寸、面积、中心坐标 |
| 门框 | 连接房间、朝向、网格坐标 |
| 火把 | 编号、位置、缩放、所属房间 |
| 宝箱 | 编号、位置、缩放、所属房间 |
| 石柱 | 编号、位置、缩放、所属房间 |
| 碎石 | 编号、网格位置与所属区域 |
| 青苔 | 编号、网格位置与所属区域 |
| 蛛网 | 编号、网格位置与所属区域 |
点击对象后会显示蓝色包围框高亮,并在右侧信息面板展示详情。
- 线框模式:观察网格、房间轮廓和实例化结构。
- 隐藏天花板:从上方查看完整平面布局。
- 动态剖切:沿当前相机方向裁切近侧结构,查看内部空间。
- 辉光后处理:按需开启 Bloom 和暗角效果。
- 聚焦按钮:快速定位到选中对象或随机房间。
- 性能自适应:低帧率时自动降低内部渲染分辨率。
| 操作 | 功能 |
|---|---|
| 鼠标左键拖拽 | 围绕地牢 360° 旋转 |
| 鼠标滚轮 | 拉近或拉远相机 |
| 鼠标右键拖拽 | 平移观察中心 |
| 点击对象 | 选中、高亮并显示结构化信息 |
R |
生成一个全新的随机地牢 |
F |
聚焦当前选中对象;未选中时聚焦随机房间 |
| 刷新未知地牢 | 使用新的时间熵种子重新生成 |
种子输入框 + Enter |
按指定种子重新生成 |
⧉ 按钮 |
复制当前种子 |
| 自动旋转 | 开关相机环绕 |
| 旋转速度 | 调整自动旋转速度 |
| 线框模式 | 切换建筑与道具线框显示 |
| 显示天花板 | 隐藏或显示顶部结构 |
| 动态剖切 | 沿相机视线裁切近侧建筑 |
| 辉光后处理 | 开关 Bloom 与暗角效果 |
| 聚焦选中 / 随机石室 | 重新定位相机观察目标 |
- Node.js
22.12+ - npm
10+ - 支持 WebGL 的现代浏览器
- Windows 桌面打包需要 Windows 10/11
生成核心位于:
src/core/dungeonGenerator.ts
整体流程:
flowchart LR
A[字符串种子] --> B[FNV-1a 32 位哈希]
B --> C[Mulberry32 随机序列]
C --> D[拒绝采样放置房间]
D --> E[构建房间完全图]
E --> F[Prim 最小生成树]
F --> G[添加少量环路]
G --> H[生成正交折线走廊]
H --> I[标记门与房间边界]
I --> J[膨胀生成石墙]
J --> K[生成火把与装饰]
K --> L[输出 DungeonData]
项目使用 FNV-1a 把任意字符串转换为稳定的 32 位无符号整数,再用 Mulberry32 产生随机序列。这个过程不依赖浏览器实现差异,因此相同种子在不同会话中会得到相同结果。
生成器在有限地图范围内使用拒绝采样:
- 房间为矩形。
- 房间之间保留石墙间距。
- 尽量避免贴边。
- 候选房间不得与已有房间重叠。
- 房间生成后按坐标排序,确保稳定编号。
连接过程分为两步:
- 以全部房间中心构建带权完全图。
- 使用 Prim 算法生成最小生成树,确保所有房间至少有一条可达路径。
- 从剩余边中随机选择少量额外连接,形成环路,减少树状死路感。
两个房间之间使用只包含一次转折的正交路径:
- 先水平后垂直,或先垂直后水平。
- 走廊默认宽度为
2格。 - 每个走廊都记录完整
path点列表。 - 路径长度用于结构化数据和后续分析。
走廊跨越房间边界的位置会生成门候选。同一个网格坐标只保留一个门,并记录:
- 连接的两个房间编号。
- 门所在的网格坐标。
- 水平或垂直朝向。
完成地板和门之后,生成器对可行走区域进行一格膨胀,得到封闭的石墙外壳。
道具由确定性随机序列生成,并写入结构化数据:
- 火把:沿房间墙面分布,保留暖色点光源和闪烁动画。
- 宝箱:偏向放置在房间角落,使用木质箱体与金属锁扣。
- 石柱:大型房间中央可能生成石柱。
- 碎石:随机分布在地板附近。
- 蜘蛛网:使用程序化透明纹理生成。
- 青苔:作为地表的低矮装饰层。
网格使用二维数组表示,单元格值如下:
| 值 | 类型 | 含义 |
|---|---|---|
0 |
EMPTY | 空区域 |
1 |
FLOOR | 可行走地板 |
2 |
WALL | 实体墙体 |
3 |
DOOR | 门或房间连接口 |
统计数据包含:
- 房间数量。
- 走廊数量。
- 门数量。
- 火把数量。
- 宝箱数量。
- 道具总数。
- 地板单元格数量。
- 墙体单元格数量。
- 本次生成耗时。
src/render/SceneManager.ts 负责:
- WebGLRenderer 初始化。
- ACES Filmic 色调映射。
- 蓝色指数雾与深蓝背景。
- PerspectiveCamera 与 OrbitControls。
- 半球光、环境光和方向光。
- 静态阴影配置。
- 动态剖切平面。
- 自适应渲染比例。
- 后处理尺寸同步。
src/render/DungeonBuilder.ts 把结构化地牢转换为 Three.js 对象:
- 地板实例。
- 墙体实例。
- 天花板实例。
- 门框、门梁和门槛实例。
- 火把与火焰实例。
- 宝箱箱体、箱盖和锁扣实例。
- 石柱实例。
- 碎石、青苔和蛛网实例。
- 房间拾取代理。
- 火把点光源与闪烁数据。
- 选中对象高亮框。
Materials.ts 创建所有 PBR 材质:
MeshStandardMaterial- 高粗糙度
- 零或低金属度
- 冷蓝石材色
- 暖色火焰自发光
- 透明蛛网材质
ProceduralTextures.ts 使用 Canvas 2D 生成:
- 石材噪点。
- 交错砖缝。
- 墙面污渍。
- 地面拼缝。
- 磨损裂纹。
- 尘埃粒子光斑。
- 蜘蛛网透明纹理。
后处理管线:
RenderPass
→ UnrealBloomPass
→ Vignette Shader
→ OutputPass
后处理默认关闭以优先保证帧率。开启后,火焰高光和亮色边缘会产生较柔和的辉光。
尘埃粒子使用单个 THREE.Points 对象:
- 数量随地图面积调整。
- 硬上限为 500。
- 使用程序化径向光斑纹理。
- 使用隔帧更新减少 CPU 开销。
- 不影响碰撞或结构化地牢数据。
项目采用冷蓝色暗黑奇幻主题:
- 深蓝背景与低密度蓝色指数雾。
- 冷蓝灰色石材与砖缝。
- 暖橙色火把光,与蓝色环境形成对比。
- 青蓝色尘埃粒子。
- 蓝色玻璃拟态 UI。
- 铜色和金色已被蓝色强调色替代。
- 所有纹理和装饰均由代码生成,不依赖外部美术资源。
重复元素使用实例化网格:
- 地板。
- 墙体。
- 天花板。
- 门柱与门梁。
- 火把。
- 火焰。
- 宝箱组件。
- 石柱。
- 碎石。
- 青苔。
- 蛛网。
这样可以显著降低 draw call 数量。
方向光阴影贴图为 1024 × 1024,并设置:
renderer.shadowMap.autoUpdate = false;阴影只在重新生成地牢时更新,不需要每帧重绘。
火把数量可能较多,但只选择少量火把创建动态 PointLight。其余火把保留自发光材质。这样可以保留灯光氛围,同时避免片元着色器承担过多动态光源。
主循环会采样 FPS:
- 低于目标帧率时降低内部渲染比例。
- 帧率恢复后逐步提高内部渲染比例。
- 最低比例受到限制,避免画面过度模糊。
- UI、CSS 和高分屏布局不受影响。
Bloom 与暗角可以完全关闭,适合低性能设备。后处理默认关闭,用户可在需要时手动开启。
Renderer 监听 WebGL 上下文丢失与恢复事件:
- 丢失时暂停绘制。
- 恢复时重新同步尺寸与阴影。
- 状态栏显示图形上下文恢复信息。
生成器只负责数据和确定性布局。Three.js 只负责把数据转换为可交互 3D 场景。这样可以在不修改 UI 的情况下替换或测试生成算法。
房间使用透明拾取代理;门框、火把、宝箱等使用实例索引映射。这样不会为了点击交互额外创建大量可见 Mesh。
npm run build通过条件:
- TypeScript 严格模式无错误。
- Vite 生产构建成功。
dist/生成完整资源。
欢迎提交 Issue、功能建议和 Pull Request。 如果这个项目对你有帮助,欢迎 Star、提交 Issue 或分享使用建议。