← Cheatsheets
Tags: unity, procedural-generation, perlin-noise, cellular-automata, l-systems, spawn-tables, seed, game-dev
Last updated: 2026-06-27
Procedural Generation Cheatsheet
Quick Reference
| Technique | Best For |
| Perlin Noise | Terrain heightmaps, caves, clouds |
| Cellular Automata | Cave systems, organic patterns |
| L-Systems | Trees, plants, branching structures |
| Spawn Tables | Loot, enemy placement, room contents |
| Voronoi / Worley Noise | Cell-like patterns, biomes |
| Wave Function Collapse | Tile-based level generation |
Perlin Noise
Unity API
float value = Mathf.PerlinNoise(x, y); # Returns 0.0–1.0
# 2D noise
float n = Mathf.PerlinNoise(x * scale, y * scale);
# 3D noise (third dimension = time / z-axis)
float n3d = Mathf.PerlinNoise(
x * scale + z * scale,
y * scale + z * scale);
Terrain Heightmap
float[,] GenerateHeightmap(int width, int height, float scale) {
float[,] map = new float[width, height];
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
map[x, y] = Mathf.PerlinNoise(
x / (float)width * scale,
y / (float)height * scale);
return map;
}
Octave Noise (Fractal / FBM)
float OctaveNoise(float x, float y, int octaves, float persistence) {
float value = 0f;
float amplitude = 1f;
float frequency = 1f;
float maxValue = 0f;
for (int i = 0; i < octaves; i++) {
value += Mathf.PerlinNoise(x * frequency, y * frequency) * amplitude;
maxValue += amplitude;
amplitude *= persistence;
frequency *= 2f;
}
return value / maxValue;
}
| Parameter | Effect | Typical |
| Octaves | Detail layers (3–8) | 4–6 |
| Persistence | Amplitude drop per octave (0–1) | 0.5 |
| Lacunarity | Frequency increase per octave | 2.0 |
| Scale | Overall zoom | 0.01–0.1 for world scale |
Noise Applications
| Use | Setup |
| Terrain height | noise > threshold = land |
| Cave generation | Separate noise for ceiling + floor |
| Ore veins | 3D noise > 0.7 = ore block |
| Biome maps | Temperature + moisture noise |
| Cloud cover | noise * alpha for transparency |
Cellular Automata
Cave Generation
bool[,] GenerateCaves(int width, int height, int iterations) {
bool[,] map = new bool[width, height];
# Step 1: Random fill (45% wall)
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
map[x, y] = Random.value < 0.45f;
# Step 2: Apply rules repeatedly
for (int i = 0; i < iterations; i++)
map = ApplyCellularRules(map);
return map;
}
bool[,] ApplyCellularRules(bool[,] map) {
int w = map.GetLength(0), h = map.GetLength(1);
bool[,] next = new bool[w, h];
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++) {
int neighbours = CountWallNeighbors(map, x, y);
if (map[x, y])
next[x, y] = neighbours >= 4; # Wall survives
else
next[x, y] = neighbours >= 5; # Empty becomes wall
}
return next;
}
Cellular Automata Rules
| Rule | Wall→ | Empty→ | Effect |
| 4-5 | Survives if ≥4 | Born if ≥5 | Standard caves |
| B5678/S45678 | Survives | Born | Dense caverns |
| B3/S12345 | Born if 3 | Survives if 1–5 | Maze-like |
L-Systems (Trees & Plants)
String Rewriting
string GenerateLSystem(string axiom, Dictionary<char, string> rules,
int iterations) {
string current = axiom;
for (int i = 0; i < iterations; i++) {
string next = "";
foreach (char c in current)
next += rules.ContainsKey(c) ? rules[c] : c.ToString();
current = next;
}
return current;
}
Plant Example
Axiom: F
Rules: F → FF+[+F-F-F]-[-F+F+F]
Angle: 25°
# F = draw forward, +/- = rotate, [/] = push/pop state (branch)
Turtle Graphics Interpreter
void DrawLSystem(string instructions, float length, float angle) {
Stack<TransformState> stack = new();
foreach (char c in instructions) {
switch (c) {
case 'F': MoveForward(length); break;
case '+': Rotate(angle); break;
case '-': Rotate(-angle); break;
case '[': stack.Push(SaveState()); break;
case ']': RestoreState(stack.Pop()); break;
}
}
}
Spawn Tables
Weighted Random
public GameObject PickWeighted(List<SpawnEntry> entries) {
float total = entries.Sum(e => e.weight);
float roll = Random.Range(0f, total);
float running = 0f;
foreach (var entry in entries) {
running += entry.weight;
if (roll <= running) return entry.prefab;
}
return entries[0].prefab;
}
Tiered Tables
public GameObject RollTiered() {
float roll = Random.value;
if (roll < 0.01f) return PickWeighted(legendaryTable); # 1%
if (roll < 0.06f) return PickWeighted(rareTable); # 5%
if (roll < 0.26f) return PickWeighted(uncommonTable); # 20%
return PickWeighted(commonTable); # 74%
}
Seed Management
Setting and Using Seeds
public int seed;
void Start() {
if (seed == 0) seed = Random.Range(1, int.MaxValue);
Random.InitState(seed);
GenerateWorld();
}
Deterministic Random
# System.Random for isolated RNG
System.Random rng = new System.Random(seed);
float randomFloat = (float)rng.NextDouble();
int randomInt = rng.Next(min, max);
# Hash-based pseudo-random for coordinate lookups
float HashNoise(int x, int y, int seed) {
int hash = seed;
hash = hash * 1664525 + x * 1013904223 + y;
hash = (hash >> 13) ^ hash;
return (float)(hash & 0x7fffffff) / 0x7fffffff;
}
Seed Debugging
[ContextMenu("Regenerate")]
void Regenerate() {
Random.InitState(seed);
GenerateWorld();
}
PlayerPrefs.SetInt("WorldSeed", seed);
Debug.Log($"World seed: {seed}");
Practical Recipes
Dungeon Room Placement
- Generate rooms with random size/position.
- Separate overlapping rooms (push apart).
- Connect rooms with corridors (A* or L-shaped).
- Place doors at corridor-room intersections.
- Populate rooms from spawn tables.
Island Generation
float[,] heightmap = GenerateHeightmap(256, 256, 0.01f);
# Apply falloff (higher edges → island shape)
for (int y = 0; y < 256; y++)
for (int x = 0; x < 256; x++) {
float dx = (x / 128f) - 1f;
float dy = (y / 128f) - 1f;
float distance = Mathf.Sqrt(dx*dx + dy*dy);
float falloff = 1f - Mathf.Clamp01(distance / 1.2f);
heightmap[x, y] *= falloff;
}
Biome Assignment
Height → Moisture ↓ | Low | Medium | High |
| High | — | Tundra | Forest |
| Mid | Desert | Grassland | Forest |
| Low | Desert | Beach | — |
Biome GetBiome(float height, float moisture) {
if (height > 0.7f) return moisture > 0.5f ? Biome.Rainforest : Biome.Tundra;
if (height > 0.4f) return moisture > 0.5f ? Biome.Forest : Biome.Grassland;
return moisture > 0.3f ? Biome.Beach : Biome.Desert;
}
Wave Function Collapse (Overview)
- Define tileset with adjacency rules (which tiles can touch).
- Start with all tiles possible in every cell (superposition).
- Collapse cell with lowest entropy to one tile.
- Propagate constraints to neighbours.
- Repeat until all cells collapsed or contradiction.
Tile Adjacency Rules
| Tile | North | East | South | West |
| Grass | Grass, Dirt | Grass, Dirt | Grass | Grass, Dirt |
| Dirt | Grass, Dirt | Dirt, Stone | Dirt, Stone | Dirt |
| Stone | Dirt, Stone | Stone | Stone | Dirt, Stone |
| Water | Water | Water, Sand | Water, Sand | Water |
| Sand | Water, Sand, Grass | Sand | Sand | Water, Sand |