Procedural Level Generation: How to Build Infinite 2D Game Worlds
Procedural level generation is the technique of creating game levels algorithmically rather than by hand. Every run of Spelunky, The Binding of Isaac, or Dead Cells produces a different layout because the levels are generated at runtime from a set of rules, not loaded from a fixed file. The result is virtually unlimited replayability from a relatively small codebase. This guide covers the core algorithms — BSP dungeon generation, cellular automata caves, and Perlin noise terrain — and how to prototype them instantly with a free browser tool.
Generate 2D levels in your browser with Jaconir 2D Procedural Level Generator — configure the algorithm, size, and parameters, and export to a tile array ready to use in your game engine.
Why Use Procedural Generation?
- Infinite replayability: Each run produces a unique layout
- Reduced content creation time: One algorithm replaces dozens of hand-made maps
- Scalable content: Change parameters to produce easy, medium, or hard layouts
- Surprise and discovery: Neither the player nor designer knows what each run contains
The tradeoff is control — handcrafted levels offer precise pacing and storytelling that procedural levels cannot. Most games that use procgen combine it with curated setpieces, fixed boss arenas, or hand-designed starting areas.
Algorithm 1: BSP Dungeon Generation
Binary Space Partitioning (BSP) is the most common algorithm for dungeon generators. It produces room-based layouts with reliable connectivity — every room is reachable.
How it works:
- Start with the full map area as a single rectangle
- Split it in half (randomly horizontal or vertical)
- Recursively split each half until regions are small enough for a single room
- Place a room inside each leaf region (with random padding)
- Connect sibling rooms with corridors, working back up the BSP tree
Result: Clean rectangular rooms connected by corridors. Predictable but feels natural. Best for dungeon crawlers, roguelikes with loot rooms, and any game where room identity matters.
// Simplified BSP split
function splitNode(node, minSize) {
const splitHorizontal = Math.random() > 0.5;
const splitPos = splitHorizontal
? Math.floor(node.y + minSize + Math.random() * (node.height - minSize * 2))
: Math.floor(node.x + minSize + Math.random() * (node.width - minSize * 2));
if (splitHorizontal) {
node.left = { x: node.x, y: node.y, width: node.width, height: splitPos - node.y };
node.right = { x: node.x, y: splitPos, width: node.width, height: node.y + node.height - splitPos };
} else {
node.left = { x: node.x, y: node.y, width: splitPos - node.x, height: node.height };
node.right = { x: splitPos, y: node.y, width: node.x + node.width - splitPos, height: node.height };
}
}
Algorithm 2: Cellular Automata Caves
Cellular automata produces organic cave-like spaces that feel natural and irregular — the opposite of BSP's clean rectangles. Used in games like Caves of Qud and many cave-themed roguelikes.
How it works:
- Fill the map randomly — each cell is wall (1) or floor (0) with a set probability (typically 45% floor)
- Apply the automata rule repeatedly (4–6 iterations): if a cell has 4 or more wall neighbours, it becomes a wall; otherwise it becomes a floor
- The random noise resolves into smooth, organic cave shapes
- Remove isolated regions to ensure connectivity
function cellularStep(grid, width, height) {
const next = grid.map((row, y) =>
row.map((cell, x) => {
let wallCount = 0;
for (let dy = -1; dy <= 1; dy++) {
for (let dx = -1; dx <= 1; dx++) {
if (dx === 0 && dy === 0) continue;
const nx = x + dx, ny = y + dy;
if (nx < 0 || nx >= width || ny < 0 || ny >= height) wallCount++;
else if (grid[ny][nx] === 1) wallCount++;
}
}
return wallCount >= 5 ? 1 : 0;
})
);
return next;
}
Algorithm 3: Perlin Noise Terrain
Perlin noise generates smooth, continuous random values that produce natural-looking terrain — rolling hills, gradual elevation changes, coherent biome shapes. Used in Minecraft, Terraria, and virtually every open-world game.
How it works: Perlin noise produces a value between -1 and 1 for any (x, y) coordinate. Values above a threshold = solid ground, below = open space. Layering multiple noise functions at different scales (octaves) produces terrain with both large features and fine detail.
// Using a noise library (simplex-noise)
import { createNoise2D } from 'simplex-noise';
const noise2D = createNoise2D();
function generateTerrain(width, height) {
return Array.from({ length: height }, (_, y) =>
Array.from({ length: width }, (_, x) => {
// Layer multiple octaves
const n = noise2D(x * 0.05, y * 0.05) * 0.6
+ noise2D(x * 0.1, y * 0.1) * 0.3
+ noise2D(x * 0.2, y * 0.2) * 0.1;
return n > 0.1 ? 1 : 0; // 1 = solid, 0 = air
})
);
}
Ensuring Connectivity
The most common problem with procedural levels is generating unreachable areas. After generating, always run a flood fill from the player start position and check that all required areas are reachable. If not, regenerate or connect isolated regions with a corridor.
function floodFill(grid, startX, startY) {
const visited = new Set();
const queue = [[startX, startY]];
while (queue.length) {
const [x, y] = queue.shift();
const key = `${ x }, ${ y }`;
if (visited.has(key) || grid[y]?.[x] !== 0) continue;
visited.add(key);
queue.push([x+1,y],[x-1,y],[x,y+1],[x,y-1]);
}
return visited;
}
Using the Procedural Level Generator
Open Jaconir 2D Procedural Level Generator, select your algorithm, configure the parameters (map size, room count, fill probability), and generate. The tool outputs a 2D tile array you can paste directly into your game engine. Regenerate until you get a layout that fits your game's needs, then export.
FAQ
Which algorithm should I use for my game?
BSP for dungeon crawlers with distinct rooms and loot placement. Cellular automata for cave exploration games with organic layouts. Perlin noise for open-world or Terraria-style terrain. Most games benefit from combining algorithms — use BSP for room layouts and cellular automata for cave sections.
How do I place enemies and items in procedurally generated levels?
After generating the tile map, identify valid placement zones (floor tiles away from the player start, dead-end rooms, etc.) and randomly place content within those zones. Weight placements by distance from start for difficulty scaling.
Can I seed procedural generation for reproducible levels?
Yes — all major random number generators accept a seed value. Using the same seed always produces the same level, enabling level sharing via seed codes (like Minecraft seeds).
Conclusion
Procedural generation turns a single algorithm into effectively unlimited content. BSP gives you reliable dungeon layouts, cellular automata gives you organic caves, and Perlin noise gives you infinite terrain. Combining them gives you a complete world generation system. Start simple with one algorithm and expand from there.
Generate your first level: Jaconir 2D Procedural Level Generator →