procedural-gen
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseProcedural generation
程序化生成
Generate levels, terrain, and loot from compact rules and a seed. The throughline
of good procgen is determinism: a single seed reproduces the same world, so
bugs are repeatable and players can share seeds. This skill owns the core
algorithms — noise, seeded RNG, dungeon layout, weighted tables; genres like
and consume it.
roguelikesurvival-crafting通过简洁的规则和种子生成关卡、地形与战利品。优质程序化生成的核心是确定性:单个种子可重现相同的世界,因此Bug可复现,玩家也能共享种子。本技能涵盖核心算法——噪声、种子式RNG、地牢布局、加权表;(类Rogue)和(生存建造)等类型游戏会用到这些算法。
roguelikesurvival-craftingWhen to use
使用场景
- Use to generate maps, dungeons, terrain heightmaps, item drops, or any content you do not want to author by hand.
- Use when results must be reproducible from a seed (debugging, daily challenges, shareable worlds).
- Use to pick weighted random outcomes (loot rarity, spawn tables).
When not to use: for the engine's tile API to paint the result, use
or . For routing AI through the generated map,
use . For carefully hand-paced levels, use — procgen and
authored design are complementary, not interchangeable.
godot-tilemapunity-tilemap-2dgame-ailevel-design- 用于生成地图、地牢、地形高度图、物品掉落,或任何不想手动制作的内容。
- 当结果需要通过种子重现时使用(调试、每日挑战、可共享世界)。
- 用于选择带权重的随机结果(战利品稀有度、刷新表)。
不适用场景:若要使用引擎的瓦片API来绘制结果,请使用或。若要让AI在生成的地图中寻路,请使用。对于精心设计的手动关卡,请使用——程序化生成与人工设计相辅相成,而非互相替代。
godot-tilemapunity-tilemap-2dgame-ailevel-designCore workflow
核心工作流程
- Own your randomness. Create one seeded RNG instance and pass it everywhere. Never call the global/static random in generation code — it makes results irreproducible and order-dependent.
- Pick the technique for the content. Continuous terrain/heightmaps → noise. Discrete rooms/corridors → space partitioning or agent-based carving. Outcomes with rarities → weighted tables.
- Generate into a plain data grid/array first, decoupled from rendering.
Generation fills or a dict; a separate pass draws it.
int[][] - Validate before shipping the result to the player. Is every room reachable? Is the spawn safe? Is there a path to the exit? Reject or repair layouts that fail; do not hand the player a broken map.
- Tune with the seed fixed so each parameter change is visible in isolation, then sweep seeds to check the distribution, not just one lucky map.
- 掌控随机性。创建一个带种子的RNG实例,并在所有需要的地方传递它。绝对不要在生成代码中调用全局/静态随机函数——这会导致结果不可重现,且依赖调用顺序。
- 为内容选择合适的技术。连续地形/高度图→噪声算法。离散房间/走廊→空间划分或基于智能体的雕刻。带稀有度的结果→加权表。
- 先生成纯数据网格/数组,与渲染解耦。生成过程填充或字典;单独通过另一步骤绘制内容。
int[][] - 在将结果交付给玩家前进行验证。每个房间都可到达吗?出生点安全吗?有通往出口的路径吗?拒绝或修复不合格的布局;不要给玩家提供有问题的地图。
- 固定种子进行调优,这样每个参数的变化都能单独观察到,然后遍历多个种子检查分布情况,而不只是依赖一张“幸运”地图。
Patterns
模式
1. Seeded, deterministic RNG (the foundation)
1. 带种子的确定性RNG(基础)
python
import random
rng = random.Random(seed) # a dedicated instance — NOT the global random.*
room_count = rng.randint(5, 12) # same seed -> same sequence, every runpython
import random
rng = random.Random(seed) # 专用实例——不要使用全局random.*
room_count = rng.randint(5, 12) # 相同种子→相同序列,每次运行结果一致RIGHT: thread rng
through every function that makes a choice.
rng正确做法:将rng
传递给所有需要做选择的函数。
rngWRONG: calling random.randint(...) (global state) — order-dependent, unseedable.
错误做法:调用random.randint(...)(全局状态)——依赖调用顺序,无法通过种子控制。
Engine equivalents: Godot `var rng = RandomNumberGenerator.new(); rng.seed = s`;
Unity `var rng = new System.Random(seed)` (or `UnityEngine.Random.InitState`).
Store the seed in the save file so a world can be regenerated.
引擎等效实现:Godot中`var rng = RandomNumberGenerator.new(); rng.seed = s`;Unity中`var rng = new System.Random(seed)`(或`UnityEngine.Random.InitState`)。将种子存储在存档文件中,以便世界可以重新生成。2. Fractal (fBm) noise for heightmaps
2. 用于高度图的分形(fBm)噪声
python
undefinedpython
undefinedSum several octaves: each higher octave has higher frequency, lower amplitude.
叠加多个八度:每个更高的八度具有更高的频率、更低的振幅。
def fbm(noise, x, y, octaves=5, lacunarity=2.0, gain=0.5):
total, amp, freq, norm = 0.0, 1.0, 1.0, 0.0
for _ in range(octaves):
total += amp * noise(x * freq, y * freq) # noise() returns ~0..1
norm += amp # track total amplitude
amp *= gain # each octave contributes less
freq *= lacunarity # ...at a higher frequency
return total / norm # normalize back into 0..1
def fbm(noise, x, y, octaves=5, lacunarity=2.0, gain=0.5):
total, amp, freq, norm = 0.0, 1.0, 1.0, 0.0
for _ in range(octaves):
total += amp * noise(x * freq, y * freq) # noise()返回~0..1
norm += amp # 跟踪总振幅
amp *= gain # 每个八度的贡献减少
freq *= lacunarity # ...频率更高
return total / norm # 归一化回0..1范围
Redistribute to carve flat valleys / sharpen peaks: higher exp -> more lowland.
重新分配值以雕刻平坦山谷/锐化山峰:指数越高→低地越多。
elevation = pow(fbm(noise, nx, ny), 2.2)
Use a real noise library (`FastNoiseLite`, `opensimplex`,
`Unity.Mathematics.noise`, or `Mathf.PerlinNoise`) — do not implement gradient
noise yourself. Seed **elevation and moisture with different seeds** so a
biome lookup over both fields isn't perfectly correlated. Full biome lookup and
island shaping are in `references/noise.md`.elevation = pow(fbm(noise, nx, ny), 2.2)
使用真实的噪声库(`FastNoiseLite`、`opensimplex`、`Unity.Mathematics.noise`或`Mathf.PerlinNoise`)——不要自己实现梯度噪声。为**海拔和湿度使用不同的种子**,这样基于这两个字段的生物群查找不会完全相关。完整的生物群查找和岛屿塑造方法在`references/noise.md`中。3. Weighted loot table (rarity-correct selection)
3. 加权战利品表(符合稀有度的选择)
python
undefinedpython
undefinedRoll proportional to weight: common drops far more often than legendary.
根据权重随机选择:普通掉落的频率远高于传奇物品。
def weighted_pick(rng, table): # table: list of (item, weight)
total = sum(w for _, w in table)
roll = rng.uniform(0, total) # a point on the cumulative line
upto = 0.0
for item, w in table:
upto += w
if roll < upto: # first bucket the roll falls into
return item
return table[-1][0] # float-safety fallback
loot = weighted_pick(rng, [("common", 70), ("rare", 25), ("legendary", 5)])
Weights need not sum to 100 — they are relative. To prevent bad streaks, use a
"pity"/bag system (see `references/dungeon-generation.md` notes on distributions).def weighted_pick(rng, table): # table: (物品, 权重)的列表
total = sum(w for _, w in table)
roll = rng.uniform(0, total) # 累积线上的一个点
upto = 0.0
for item, w in table:
upto += w
if roll < upto: # 骰子落入的第一个区间
return item
return table[-1][0] # 浮点数安全回退
权重不需要总和为100——它们是相对值。为了避免连续坏结果,可以使用“保底”/背包系统(详见`references/dungeon-generation.md`中关于分布的说明)。4. Rooms-and-corridors dungeon (sketch)
4. 房间+走廊地牢(草图)
python
undefinedpython
undefined1. Place non-overlapping rooms; 2. connect them; 3. carve into the grid.
1. 放置不重叠的房间;2. 连接它们;3. 在网格中雕刻。
rooms = []
for _ in range(attempts):
r = Rect(rng.randint(1, W-w-1), rng.randint(1, H-h-1), w, h)
if not any(r.intersects(o.expand(1)) for o in rooms): # keep a 1-tile gap
rooms.append(r)
for a, b in zip(rooms, rooms[1:]): # connect each room to the next
carve_l_corridor(grid, a.center, b.center, rng) # horizontal then vertical
The complete generator (BSP partitioning, L-corridors, reachability check, and
random-walk caves) is in `references/dungeon-generation.md`.rooms = []
for _ in range(attempts):
r = Rect(rng.randint(1, W-w-1), rng.randint(1, H-h-1), w, h)
if not any(r.intersects(o.expand(1)) for o in rooms): # 保持1格间距
rooms.append(r)
for a, b in zip(rooms, rooms[1:]): # 将每个房间与下一个连接
carve_l_corridor(grid, a.center, b.center, rng) # 先水平后垂直
完整的生成器(BSP划分、L型走廊、可达性检查、随机游走洞穴)在`references/dungeon-generation.md`中。Pitfalls
常见陷阱
- Using the global RNG inside generation makes worlds unreproducible and breaks the moment call order changes. Always pass a seeded instance.
- Correlated noise fields: sampling elevation and moisture from the same seed/offset produces biomes that line up in bands. Offset or reseed each field.
- Octave artifacts: adding octaves without renormalizing pushes values out of
; divide by the summed amplitude (and beware library output ranges — some return
0..1, some-1..1).0..1 - No connectivity check: rooms or caves can end up isolated. Flood-fill from the spawn and discard/reconnect unreachable regions before play.
- Unbounded placement loops: "keep trying until N rooms fit" can spin forever on a small grid. Cap attempts and accept fewer rooms.
- Seeding once globally, then relying on frame timing: any non-deterministic input (time, physics, hash randomization) leaking into generation destroys reproducibility.
- 在生成中使用全局RNG会导致世界不可重现,且调用顺序改变时会出错。始终传递带种子的实例。
- 相关噪声场:从相同种子/偏移量采样海拔和湿度会导致生物群呈带状排列。为每个字段设置偏移量或重新设置种子。
- 八度伪影:叠加八度而不归一化会使值超出范围;需除以总振幅(注意库的输出范围——有些返回
0..1,有些返回-1..1)。0..1 - 无连通性检查:房间或洞穴可能会被孤立。从出生点进行洪水填充,在游戏开始前丢弃/重新连接不可达区域。
- 无限制放置循环:“不断尝试直到放置N个房间”在小网格上可能无限循环。限制尝试次数,接受更少的房间。
- 全局单次播种,然后依赖帧计时:任何非确定性输入(时间、物理、哈希随机化)渗入生成过程都会破坏可重现性。
References
参考资料
- — octaves/lacunarity/gain, redistribution, island shaping, two-axis biome lookup, blue-noise object scatter.
references/noise.md - — BSP, rooms+corridors, random-walk caves, cellular-automata smoothing, connectivity validation, distribution/pity tables.
references/dungeon-generation.md
- ——八度/ lacunarity/增益、重分配、岛屿塑造、双轴生物群查找、蓝噪声对象散布。
references/noise.md - ——BSP、房间+走廊、随机游走洞穴、元胞自动机平滑、连通性验证、分布/保底表。
references/dungeon-generation.md
Related skills
相关技能
- ,
godot-tilemap— paint the generated grid into the engine.unity-tilemap-2d - — pathfinding over the generated graph.
game-ai - — pacing and hand-authored structure that procgen complements.
level-design - ,
roguelike— genres that compose this skill.survival-crafting
- 、
godot-tilemap——将生成的网格绘制到引擎中。unity-tilemap-2d - ——在生成的图上寻路。
game-ai - ——程序化生成所补充的节奏控制和人工设计结构。
level-design - 、
roguelike——使用本技能的游戏类型。survival-crafting