世界生成流程
基本信息
| 属性 | 值 |
|---|---|
| 世界生成器 | greymerk.roguelike.DungeonGenerator implements IWorldGenerator(DungeonGenerator.java:10) |
| 注册 | GameRegistry.registerWorldGenerator(worldGen, 0)(Roguelike.java:34) |
| 优先级 | 0 |
| 实例 | Roguelike.worldGen = new DungeonGenerator()(Roguelike.java:30) |
| 同名类 | ⚠️ 仓库里有两个 DungeonGenerator,见下文 |
| 维度支持 | 不限维度;跨维度开关由 dimensionWL / dimensionBL 与 biome 白名单控制 |
⚠️ 两个同名 DungeonGenerator
find . -name 'DungeonGenerator.java' 命中两个文件,二者无继承关系、职责完全不同:
| 全限定名 | 行数 | 角色 |
|---|---|---|
greymerk.roguelike.DungeonGenerator |
21 | 实现 IWorldGenerator,是唯一被注册的世界生成器 |
greymerk.roguelike.dungeon.DungeonGenerator |
66 | 内部编排器,负责逐层调用 LevelGenerator 并在末尾建塔 |
引用时必须带包名。仅写 DungeonGenerator 会有歧义。
功能
自然生成链路:
IWorldGenerator.generate(random, chunkX, chunkZ, world, cg, cp) DungeonGenerator.java:13
└─ new WorldEditor(world)
└─ new Dungeon(editor)
└─ dungeon.spawnInChunk(random, chunkX, chunkZ) Dungeon.java:146
└─ Dungeon.canSpawnInChunk(chunkX, chunkZ, editor) Dungeon.java:112
└─ generateNear(rand, chunkX*16+4, chunkZ*16+4) Dungeon.java:149-152
spawnInChunk 把区块坐标换算成方块坐标并固定偏移 +4(Dungeon.java:149-150),因此地牢不会贴着区块边界生成。
真正的生成入口是 dungeon/DungeonGenerator.generate(:24-61):自 TOPLEVEL = 50(:16)起,每层向下 VERTICAL_SPACING = 10(:15),逐层 level.generate(...),全部完成后再在 (inX, 50, inZ) 建塔。
区块网格算法
Dungeon.canSpawnInChunk(dungeon/Dungeon.java:112-144)用确定性网格决定哪些区块出地牢:
| 步骤 | 公式 | 来源 |
|---|---|---|
| 频率取值 | frequency = RogueConfig.getInt(SPAWNFREQUENCY) |
Dungeon.java:118 |
| 网格下界 | min = 8 * frequency / 10,再 min < 2 ? 2 : min |
:119,122 |
| 网格上界 | max = 32 * frequency / 10,再 max < 8 ? 8 : max |
:120,123 |
| 负坐标修正 | tempX = chunkX < 0 ? chunkX - (max - 1) : chunkX(Z 同样) |
:125-126 |
| 网格索引 | m = tempX / max,n = tempZ / max |
:128-129 |
| 种子随机 | editor.getSeededRandom(m, n, 10387312) |
:131 |
| 命中判定 | chunkX == m && chunkZ == n 才返回 true |
:139-141 |
用默认值 spawnFrequency = 10 代入:min = 8、max = 32,即每 8×8 至 32×32 个区块的网格内随机命中 1 个区块。种子固定为 10387312 且只依赖网格索引 (m, n),因此同一世界内地牢位置可复现,且与玩家是否探索过无关。
选址合法性
Dungeon.validLocation(dungeon/Dungeon.java:165-189)逐项排除:
| 检查 | 规则 | 来源 |
|---|---|---|
| biome 黑名单 | RIVER、BEACH、MUSHROOM、OCEAN 四类命中即否决 |
:168-174 |
| 起始高度 | upperLimit = RogueConfig.getInt(UPPERLIMIT)(默认 100) |
:176,179 |
| 起点必须是空气 | if (!editor.isAirBlock(cursor)) return false; |
:181-183 |
| 向下找地面 | 循环 validGroundBlock + Cardinal.DOWN,跌破 lowerLimit(默认 60)即否决 |
:185-187 |
| 水中否决 | 途经方块 Material.water 即否决 |
:188 |
楼层难度分层
Dungeon.getLevel(int y)(dungeon/Dungeon.java:156-163)按 Y 高度返回 0–4 的难度层级:
| Y 区间 | getLevel() |
|---|---|
y >= 45 |
0 |
35 <= y < 45 |
1 |
25 <= y < 35 |
2 |
15 <= y < 25 |
3 |
y < 15 |
4 |
该值作为 level 参数传入 Loot.addEquipment(treasure/loot/Loot.java:109)与各类战利品 provider,决定装备品质与附魔强度。
数值
| 数值名 | 值 | 来源 |
|---|---|---|
| 塔基 Y | TOPLEVEL = 50 |
dungeon/DungeonGenerator.java:16 |
| 楼层垂直间距 | VERTICAL_SPACING = 10 |
dungeon/DungeonGenerator.java:15 |
| 网格随机种子 | 10387312 |
dungeon/Dungeon.java:131 |
| 区块内偏移 | +4 / +4 | dungeon/Dungeon.java:149-150 |
| 最低网格下界 | 2 | dungeon/Dungeon.java:122 |
| 最低网格上界 | 8 | dungeon/Dungeon.java:123 |
| 难度层级数 | 5(0–4) | dungeon/Dungeon.java:156-163 |
| 最高可用房间数 | levelMaxRooms,默认 30 |
dungeon/base/DungeonFactory.java:61 |
交互
| 触发 | 行为 |
|---|---|
| 区块加载 | DungeonGenerator.generate → 网格判定 → 命中则生成 |
/roguelike dungeon ... |
跳过网格判定,直接在指定坐标走同一套 Dungeon.generate |
doNaturalSpawn = false |
canSpawnInChunk 第一行即返回 false,自然生成完全关闭(dungeon/Dungeon.java:114-116) |
| 单层生成抛异常 | catch (Exception e) { e.printStackTrace(); }(dungeon/DungeonGenerator.java:45-47)后继续下一层;该层仍被加入 levels 列表(:55),随后 generator.getEnd() 被调用(:50)——若异常发生在 getEnd() 就绪之前会连带失败 |
相关条目
- 生成条件 - biome 与维度的白/黑名单判定
- JSON 地牢设置包 - 决定生成哪套主题与房间池
- 塔 - 生成流程的收尾步骤
- 地牢房间 - 逐层铺开的房间
- 配置项 -
doNaturalSpawn/spawnFrequency/upperLimit/lowerLimit