※本記事は、筆者(roripika)の実際のゲーム開発(C++ / Axmol Engine『losthistoria』)における実体験・開発ログをもとに、ペアプログラミングAIエージェント(Antigravity)が構成・執筆のサポートを行ってお送りしています。
1. はじめに:個人開発レベルデザインの限界と「考慮漏れ」の恐怖
個人開発や小規模チームでのゲーム開発において、最も頭を悩ませる作業の一つが**「レベルデザイン(ゲームバランス調整)」**です。
- 「敵のHPや攻撃力を勘で設定したら、詰みステージやガバガバなステージが量産された」
- 「開発が進んでから『ダメージ計算式の考慮漏れ』や『新スキルの仕様追加』が発動し、全数百ステージのパラメータを手作業で修正する絶望を味わった」
このような経験はないでしょうか?
本記事では、現在C++ / Axmolエンジンで開発中の本格アクションRPG『losthistoria』において、**「数値を手打ちするのを一切やめ、AIとPythonシミュレータによって『適正クリア』と『低レベル全滅』を自動決定・証明する仕組み」**を構築したノウハウを共有します。
この仕組みを導入したことで、後からレベルデザインの大きな考慮漏れや仕様変更が発生しても、1コマンド(約1分)で全ステージのバランス再調整と自動検証が完結するようになりました。
2. 従来の手打ちレベルデザインの限界
従来のゲーム開発では、以下のような流れでレベルデザインが行われがちです。
[プランナー] 勘で敵HP/ATKをJSONに手打ち
➔ [テストプレイ] 開発者自身がプレイして「ちょっと強いかも」と微調整
➔ [ステージ増加] ステージ数が50, 100と増えて管理不能に
➔ [トラブル発生] 「特定の職のパッシブスキル計算が抜けていた」等の考慮漏れが発覚
➔ [絶望] 全100ステージの敵パラメータを手作業で再計算・修正(数十時間のロス)
開発者自身がテストプレイを繰り返すと操作に熟練してしまい、「ちょうどいい難易度」の感覚が麻痺する問題もあります。
そこで本プロジェクトでは、**「人間は高レベルの意図だけを書き、具体的な数値と検証はAI/シミュレータに任せる」**という原則へ全面的にシフトしました。
3. 設計思想:「意図」と「数値生成」の完全分離
レベルデザインのパイプラインを以下のように分離しました。
【人間の役割】設計シートに「高レベルの意図」だけを書く
└ 地域名 / 推奨レベル / 登場する敵の種類 / WAVE数
│
▼
【シミュレータ+AI】`tools/battle_sim.py --fit`
└ C++ゲーム本編の計算式を完全再現したPythonシミュレータが敵HP/ATK倍率を逆算
└ 「推奨Lvならクリア ∧ 推奨Lv-Nでは全滅」を満たす数値を決定論的に探索
│
▼
【データ&自動証明】`Content/data/wave_table.json` の自動更新
└ 人手によるマジックナンバーを一切残さず、E2Eテストで全ステージのクリア可否を自動証明
人間が触る領域を「意図の設定」だけに限定することで、パラメータの手打ちを完全に排除しました。
4. 「適正クリア」と「低レベル全滅」を数学的に証明する
単に「クリアできる」だけでなく、**「適正な難易度ゲート(低レベルではクリアできないこと)」**を自動探索・証明するために、以下の基準をシミュレータに組み込みました。
基準1: クリア余裕バンド
想定パーティが推奨レベルで挑んだ場合、**「残HP 約20%〜65%」「所要時間 約25秒〜45秒/ステージ」**でクリアできる数値をターゲットとします。
基準2: 難易度ゲート(gap)
推奨レベルから一定レベル(gap)低いパーティで挑んだ場合、**必ず全滅する(クリア不可)**ことを証明します。
💡 レベルデザインでハマった「高レベル帯のトラップ」
シミュレータの開発中、非常に重要な知見が得られました。
「推奨レベルより3レベル低ければ全滅」という固定値ルール(
gap = 3)を作ると、高レベル帯で破綻する。
ステータスの成長曲線において、高レベル帯になるほど「1レベルあたりのステータス上昇率(戦力比)」は小さくなります。そのため、Lv70のステージで固定「3Lv差(Lv67)」にしても、戦力差が数%しかなく、難易度ゲートとして機能せずクリアできてしまうのです。
この問題を解決するため、ゲート幅 gap を推奨レベルに比例した動的計算に変更しました。
$$\text{gap} = \max(2, ; \text{round}(\text{推奨Lv} \times 0.12))$$
これにより、序盤は2〜3レベル差、終盤は7〜8レベル差という、ゲーム全体を通して適正な難易度ハードルが自動的に維持されるようになりました。
5. 本体のC++計算式と完全同期したPythonシミュレータ
シミュレータ(tools/battle_sim.py)は、C++のゲーム本編の計算式と厳密に一致させています。
# C++ (UnitData::calculateStats, DamageCalculator::calcDamage) と完全一致するPython実装例
def calc_damage(atk, target_def, elem_bonus=1.0):
# 防具DEFによる減衰式: ATK * (1 - DEF / (DEF + 100))
def_mitigation = 1.0 - (target_def / (target_def + 100.0))
raw_damage = atk * elem_bonus * def_mitigation
return max(1, int(raw_damage))
def calc_cooltime(speed):
# 素早さからクールタイム(行動間隔)への写像
return max(1.0, min(5.0, 5.0 - speed * 0.004))
シミュレータ側は「装備なし(DEF=0)」「必殺スキルは一定周期発動」という**プレイヤーを少し過小評価する前提(安全側のマージン)**で計算を行います。実戦ではプレイヤーのパズル精度や装備によって少し有利になるため、絶妙な手応えが得られるよう調整されています。
6. 【真骨頂】考慮漏れが発生しても「1分」で手戻り完了
この仕組みの真価は、**「開発後半で大きな考慮漏れや仕様変更が発生したとき」**に発揮されます。
実際にあったシナリオ
開発中、「オラクル(僧侶職)のスキルを『全体リジェネ』から『死亡した味方を蘇生するリザレクション』に差し替える」という大きな仕様変更が発生しました。
さらに、「シミュレータ側で特定職業のパッシブスキルによる属性バフ計算が漏れていた」という考慮漏れも判明。
従来の開発なら…
- 味方の回復量・耐久性能の前提がガラリと変わるため、全ステージの敵ATK/HPを調整し直し。
- 100ステージ以上を手作業で修正&プレイテストし直すのに数日〜数週間が吹き飛ぶ。
AI+自動フィッティング環境の場合
-
AI(Antigravity)に指示:
「オラクルの新スキル『リザレクション』のHP復元率と、バフ計算の修正を
battle_sim.pyに反映して、全ステージのwave_table.jsonを再フィッティングして」 -
実行: AIが数秒でシミュレータコードを修正し、
python3 tools/battle_sim.py --fitを自動実行。 - 結果: 約1分で全ステージの敵ステータス倍率が一括再計算され、すべてのステージで「推奨Lvクリア ∧ 低Lv全滅」の検証(E2E PASS)が完了!
// 自動更新された Content/data/wave_table.json
{
"stage_ruins_03": {
"recommended_level": 15,
"enemy_hp_scale": 1.42, // 1分で最適な倍率に再フィッティング
"enemy_atk_scale": 1.18,
"simulation_result": "PASS (RecLv: Clear [HP 35%], RecLv-3: Wiped Out)"
}
}
手作業による修正コスト・確認コストが完全にゼロになりました。
7. まとめ:AI時代のレベルデザインの心構え
ゲーム開発におけるレベルデザインの自動化を通して学んだ最も重要な結論は、以下の一言に尽きます。
「最初から完璧なバランスを狙うな。何度でも1秒で全修正できる仕組み(パイプライン)を先に作れ。」
ポイントの復習
- 意図と数値の分離: 人間は「どう楽しませたいか(意図)」だけを定義し、数値はシミュレータに計算させる。
-
証明可能な難易度ゲート: 「クリアできる」だけでなく「低レベルでは勝てない(動的な
gap)」を数値的に自動証明する。 - AIとの協業: 考慮漏れや仕様変更が起きても、AIにシミュレータの前提式を直させれば、一瞬で全データの再フィッティング&検証が完了する。
レベルデザインの数値調整に忙殺されている個人開発者やプランナーの方は、ぜひ「シミュレータ+AIによる自動再フィッティング」の仕組みを導入してみてください!
筆者注: 本記事で紹介したゲーム『losthistoria』は、C++ / Axmol Engineにて開発中のダークファンタジーRPGです。