procedural-gen について
procedural-gen は、ルールとシードからレベル、地形、戦利品を生成するゲーム開発向けスキルです。再現性、接続性の検証、生成データと描画の分離を重視します。
主な機能
- 01シードによる決定論的生成
- 02ノイズによる地形・高度マップ生成
- 03部屋・通路・洞窟のレイアウト
- 04重み付き戦利品の選択
- 05接続性の検証
活用シーン
- 01再現可能なダンジョンマップの生成
- 02地形やバイオームの構築
- 03レア度に応じたアイテムドロップ
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill procedural-genインストール後、Claude Code で/procedural-genを入力して読み込まれたか確認します。
同梱ファイルreferences/dungeon-generation.mdreferences/noise.md
詳細
プロシージャル生成
コンパクトなルールとシードから、レベル、地形、戦利品を生成します。優れたプロシージャル生成に欠かせないのは、決定性です。単一のシードで同じ世界を再現できれば、バグを再現でき、プレイヤー同士でシードを共有できます。このスキルでは、ノイズ、シード付き RNG、ダンジョンレイアウト、重み付きテーブルなど、中核となるアルゴリズムを扱います。roguelike や survival-crafting などのジャンルがこれを利用します。
使用する場面
- マップ、ダンジョン、地形の高さマップ、アイテムドロップなど、手作業で作成したくないコンテンツの生成に使用します。
- シードから再現可能な結果が必要な場合(デバッグ、デイリーチャレンジ、共有可能なワールド)に使用します。
- 重み付きのランダムな結果(戦利品のレア度、スポーンテーブル)の選択に使用します。
使用しない場面: 生成結果を描画するためのエンジンのタイル API には、godot-tilemap または unity-tilemap-2d を使用します。生成されたマップ内で AI を経路探索させるには、game-ai を使用します。丁寧に手作業でペース配分したレベルには、level-design を使用します。プロシージャル生成と手作業によるデザインは相互補完的であり、置き換え可能なものではありません。
基本的なワークフロー
- 乱数を自分で管理します。 シード付き RNG インスタンスを 1 つ作成し、あらゆる場所に渡します。生成コードでグローバルまたは静的な乱数を呼び出してはいけません。結果が再現できず、呼び出し順にも依存するようになります。
- コンテンツに合った手法を選びます。 連続的な地形/高さマップ → ノイズ。離散的な部屋/通路 → 空間分割またはエージェントによる掘削。レア度のある結果 → 重み付きテーブル。
- まずプレーンなデータグリッド/配列に生成します。 描画とは切り離してください。生成処理では
int[][]または辞書にデータを格納し、別の処理で描画します。 - プレイヤーに結果を渡す前に検証します。 すべての部屋に到達できますか? スポーン地点は安全ですか? 出口までの道はありますか? 条件を満たさないレイアウトは却下または修正し、壊れたマップをプレイヤーに渡してはいけません。
- シードを固定して調整します。 そうすることで各パラメーター変更の影響を個別に確認できます。その後、シードを複数試して、運のよいマップ 1 つだけでなく分布を確認します。
パターン
1. シード付きの決定的 RNG(基礎)
import random
rng = random.Random(seed) # a dedicated instance — NOT the global random.*
room_count = rng.randint(5, 12) # same seed -> same sequence, every run
# RIGHT: thread `rng` through every function that makes a choice.
# WRONG: calling random.randint(...) (global state) — order-dependent, unseedable.
エンジンでの同等の方法:Godot では var rng = RandomNumberGenerator.new(); rng.seed = s、Unity では var rng = new System.Random(seed)(または UnityEngine.Random.InitState)です。ワールドを再生成できるよう、セーブファイルにシードを保存します。
2. 高さマップ用のフラクタル(fBm)ノイズ
# Sum 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
# Redistribute to carve flat valleys / sharpen peaks: higher exp -> more lowland.
elevation = pow(fbm(noise, nx, ny), 2.2)
実績のあるノイズライブラリ(FastNoiseLite、opensimplex、Unity.Mathematics.noise、または Mathf.PerlinNoise)を使い、勾配ノイズを自分で実装してはいけません。**標高と湿度には異なるシードを設定します。**そうしないと、両方のフィールドを使ったバイオーム検索の相関が完全になってしまいます。バイオーム検索の全体像と島の形状作成については、references/noise.md を参照してください。
3. 重み付き戦利品テーブル(レア度に応じた選択)
# Roll 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)])
重みの合計を 100 にする必要はありません。重みは相対値です。好ましくない連続結果を防ぐには、「天井」/バッグ方式を使います(分布に関するメモは references/dungeon-generation.md を参照してください)。
4. 部屋と通路のダンジョン(概要)
# 1. Place non-overlapping rooms; 2. connect them; 3. carve into the grid.
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
完全な生成器(BSP 分割、L 字型通路、到達可能性チェック、ランダムウォーク洞窟)は references/dungeon-generation.md にあります。
注意点
- 生成処理でグローバル RNG を使うこと:ワールドの再現性が失われ、呼び出し順序が変わっただけでも結果が変わります。必ずシードを指定したインスタンスを渡してください。
- 相関したノイズフィールド:標高と湿度を同じシード/オフセットからサンプリングすると、帯状に並ぶバイオームが生成されます。各フィールドのオフセットを変えるか、シードを設定し直してください。
- オクターブによるアーティファクト:正規化せずにオクターブを追加すると、値が
0..1の範囲を外れます。振幅の合計で割ってください(また、ライブラリの出力範囲にも注意してください。一部は-1..1を返し、別のものは0..1を返します)。 - 接続性チェックを行わないこと:部屋や洞窟が孤立することがあります。プレイ開始前にスポーン地点からフラッドフィルを行い、到達不能な領域を破棄するか、再接続してください。
- 配置ループに上限を設けないこと:「N 個の部屋が配置できるまで試す」処理は、グリッドが小さいと永久に回り続ける可能性があります。試行回数に上限を設け、部屋の数が少なくなることを許容してください。
- グローバルに一度だけシードを設定し、その後フレームタイミングに依存すること:時間、物理演算、ハッシュのランダム化など、非決定的な入力が生成処理に入り込むと、再現性が失われます。
参考資料
references/noise.md— オクターブ/ラクナリティ/ゲイン、再分布、島の形状設定、2 軸によるバイオーム検索、ブルーノイズによるオブジェクト散布。references/dungeon-generation.md— BSP、部屋と通路、ランダムウォークによる洞窟生成、セル・オートマトンによる平滑化、接続性の検証、分布/救済テーブル。
関連スキル
godot-tilemap、unity-tilemap-2d— 生成したグリッドをエンジン上に描画します。game-ai— 生成したグラフ上で経路探索を行います。level-design— プロシージャル生成を補完する、ペース配分と手作業による構成。roguelike、survival-crafting— このスキルと組み合わせるジャンル。