ステージシステム設計¶
§1 データ構造¶
Resource 階層¶
ステージの静的データは 3 層の Resource で構成される。
StageData (stage_data.gd)
├── enemy_placements: Array[EnemyPlacement]
│ └── EnemyPlacement (enemy_placement.gd)
│ ├── grid_index: int (0〜8)
│ └── unit: UnitData
├── bonus_conditions: Array[BonusCondition]
│ └── BonusCondition (bonus_condition.gd)
│ ├── condition_type: ConditionType
│ └── threshold: int
├── reward_units: Array[UnitData]
└── background_path: String
StageData フィールド一覧¶
| フィールド | 型 | 説明 |
|---|---|---|
id |
StringName |
ステージの一意識別子(例: &"forest") |
enemy_placements |
Array[EnemyPlacement] |
敵ユニットの配置と行動順(§2 参照) |
bonus_conditions |
Array[BonusCondition] |
ボーナス条件の定義 |
reward_units |
Array[UnitData] |
クリア報酬ユニット |
background_path |
String |
背景画像パス(res:// 形式) |
EnemyPlacement フィールド一覧¶
| フィールド | 型 | 説明 |
|---|---|---|
grid_index |
int (0〜8) |
3×3 グリッド上の配置位置。座標変換: docs/design/battle_system.md §1 |
unit |
UnitData |
敵ユニットのデータ |
grid_index と座標の対応¶
→ 味方陣
┌─────┬─────┬─────┐
│ 0 │ 1 │ 2 │ 行 0(上段)
├─────┼─────┼─────┤
│ 3 │ 4 │ 5 │ 行 1(中段)
├─────┼─────┼─────┤
│ 6 │ 7 │ 8 │ 行 2(下段)
└─────┴─────┴─────┘
列0 列1 列2
前衛 中衛 後衛
変換式: Vector2i(grid_index % 3, grid_index / 3)
注記: 敵グリッドの座標系は味方グリッドと同じ構造だが、画面上は左右反転して表示される。座標系のルールは
battle_system.md§1 を参照。
ファイル配置規約¶
| 種別 | ディレクトリ | 命名規約 | 例 |
|---|---|---|---|
| ステージデータ | data/stages/ |
stage_{id}.tres |
stage_forest.tres |
| ユニット | data/units/ |
{id}.tres |
goblin.tres |
| スキル | data/skills/ |
{id}.tres |
basic_attack.tres |
ユニットは味方・敵の区別なく同一ディレクトリに配置する。
UnitDataはサイドニュートラルであり、味方として出陣するか敵として配置されるかは実行時のコンテキスト(BattleUnit.Side)で決まる。
i18n 翻訳キー規約¶
| 種別 | キーパターン | 例 |
|---|---|---|
| ステージ名 | STAGE_{ID}_NAME |
STAGE_FOREST_NAME |
| ステージ説明 | STAGE_{ID}_DESC |
STAGE_FOREST_DESC |
翻訳ファイル: translations/translations.csv
§2 敵行動順¶
設計原則¶
enemy_placements 配列の順序がそのまま敵の行動順になる。
これは以下の設計判断に基づく:
- データの一元管理: 配置位置(
grid_index)と行動順(配列内の位置)を同じ構造体で管理することで、「配置されているが行動順に含まれない」「行動順に含まれるが配置されていない」といったデータ不整合を構造的に排除する - レベルデザインの直感性:
.tresファイルでenemy_placementsの要素を並べ替えるだけで行動順を変更できる。別途enemy_action_order配列を管理する必要がない - Fail Fast:
validate_enemy_placements()によるロード時検証で、grid_indexの範囲外・重複・null ユニットを即座にクラッシュさせる(PRD #34 DP-1)
行動順の決定フロー¶
StageData.enemy_placements = [ep_A, ep_B, ep_C]
↓
行動順: ep_A(1番目) → ep_B(2番目) → ep_C(3番目)
↓
battle.gd._build_battle_units_from_grid() が
enemy_placements の順序で BattleUnit 配列を構築
↓
BattleEngine が BattleUnit 配列の順序で行動を実行
具体例¶
# stage_forest.tres の enemy_placements
[ep_goblin_a, ep_goblin_b]
ep_goblin_a: grid_index = 3 (中段・前衛)
ep_goblin_b: grid_index = 7 (下段・中衛)
→ 行動順: goblin_a(3) → goblin_b(7)
→ 前衛のゴブリンが先に行動し、中衛のゴブリンが後に行動する
行動順を逆にしたい場合は、配列の順序を入れ替えるだけでよい:
[ep_goblin_b, ep_goblin_a]
→ 行動順: goblin_b(7) → goblin_a(3)
→ 中衛のゴブリンが先に行動する
味方側の行動順との比較¶
| 側 | 行動順の決定方式 | 管理場所 |
|---|---|---|
| 味方 | プレイヤーが準備フェーズで設定する | PreparationController._action_order |
| 敵 | StageData.enemy_placements 配列の順序 |
.tres ファイル |
味方も敵も
Array[BattleUnit]の順序でBattleEngineに渡される点は同じ。順序の決定方式だけが異なる。
バリデーション¶
StageData.validate_enemy_placements() が以下を検証する:
| 検証項目 | 違反時の挙動 |
|---|---|
EnemyPlacement が null |
assert でクラッシュ |
grid_index が 0〜8 の範囲外 |
assert でクラッシュ |
unit が null |
assert でクラッシュ |
grid_index の重複 |
assert でクラッシュ |
§3 ステージ選択画面¶
画面遷移¶
ホーム画面
└─ 「出撃」ボタン
└─ SceneManager.push_scene() → ステージ選択画面
├─ ステージボタン押下
│ └─ SceneManager.push_scene(battle, {stage_data: StageData})
└─ 「戻る」ボタン
└─ SceneManager.pop_scene() → ホーム画面
データ供給方式(DP-2)¶
ステージデータの .tres パスは stage_select.gd 内の定数配列で管理する。
const _STAGE_PATHS: Array[String] = [
"res://data/stages/stage_forest.tres",
"res://data/stages/stage_cave.tres",
"res://data/stages/stage_ruins.tres",
"res://data/stages/stage_swamp.tres",
"res://data/stages/stage_volcano.tres",
]
配列の順序がステージのプレイ順序(リニア進行)を定義する。 プレイヤーは配列の先頭から順にステージを解放していく。
Phase 2 移行計画: ステージ数が増加した場合は
GameDataRegistryのレジストリパターンに移行する。GameDataRegistryは既にdata/stages/を走査する機能を持っているため、移行コストは低い。
表示内容¶
各ステージボタンには以下が表示される:
| 要素 | 表示形式 | データソース |
|---|---|---|
| ステージ名 | StageData.get_display_name() |
翻訳キー |
| クリアマーク | ✅(クリア済みの場合) | SaveManager.is_stage_cleared() |
pop 時のクリアマーク更新¶
バトル勝利後に SceneManager.pop_scene() でステージ選択画面に戻った際、on_scene_entered() が呼ばれ、全ステージのクリアマークが再描画される。これにより、クリア直後のステージに即座にマークが表示される。
ステージ解放方式(リニア進行)¶
ステージはリニア進行制で解放される(GDD §3「ステージ進行方式」、Issue #250 で確定)。
| ルール | 詳細 |
|---|---|
| 初期状態 | 最初のステージ(_STAGE_PATHS[0])のみ解放済み |
| 解放条件 | ステージ N をクリアすると、ステージ N+1 が解放される |
| 判定方式 | SaveManager.is_stage_cleared(stage.id) で前ステージのクリア状態を確認 |
| 表示 | 未解放ステージはロック表示(グレーアウト + 🔒)。選択不可 |
| デバッグモード | debug_mode = true の場合、全ステージが解放済みとして表示される |
設計意図: リニア進行により、弱点チェーン(前ステージの報酬ユニットが次ステージで有効)をデザイナーが確実に制御できる。また、ストーリー進行やキャラクター親密度イベントの解放条件を段階的に定義可能になる。
§4 バトル連携¶
StageData の受け渡し¶
ステージ選択画面
└─ SceneManager.push_scene(battle_path, {"stage_data": stage_data})
└─ battle.gd.on_scene_entered(params)
└─ _stage_data = params["stage_data"]
初期化フロー¶
battle.gd の初期化は以下の順序で行われる:
_ready()
├─ UI・コントローラのセットアップ
├─ _initialize_data.call_deferred() ← 遅延呼び出し
└─ (return)
on_scene_entered(params) ← SceneManager が _ready() 後に呼ぶ
└─ _stage_data を保存
_initialize_data() ← call_deferred で実行(on_scene_entered の後)
├─ _setup_stage_data()
│ ├─ _stage_data != null → StageData からグリッド構築
│ └─ _stage_data == null → BattleDebugData フォールバック
├─ リトライ復元(BattleState.has_retry_data())
└─ デバッグモード自動配置
なぜ
call_deferredが必要か: SceneManager はadd_child()→on_scene_entered()の順で呼ぶが、_ready()はadd_child()時に発火する。そのため_ready()時点では_stage_dataがまだ null である。call_deferredにより、on_scene_entered()で_stage_dataが設定された後にデータ初期化を実行する。
敵グリッド構築¶
# _stage_data が設定されている場合
_stage_data.validate_enemy_placements() # Fail Fast (DP-1)
_enemy_grid.load_from_array(_stage_data.to_grid_array())
_bonus_conditions = _stage_data.bonus_conditions
敵行動順の構築¶
_build_battle_units_from_grid() が _stage_data.enemy_placements の順序で BattleUnit 配列を構築する(§2 参照)。
debug_mode フォールバック¶
_stage_data が null の場合(エディタからバトルシーンを直接起動した場合等)は BattleDebugData の仮データにフォールバックする。これにより既存の開発ワークフローが維持される。
参照リンク¶
| ドキュメント | リンク |
|---|---|
| ステージシステム PRD | #34 |
| ユニットシステム設計 | docs/design/unit_system.md |
| effect_offsets 座標系 | docs/design/battle_system.md §1 |
| GDD §3 コアメカニクス | docs/gdd.md |
| StageData 実装 | scripts/data/stage_data.gd |
| EnemyPlacement 実装 | scripts/data/enemy_placement.gd |
| BonusCondition 実装 | scripts/data/bonus_condition.gd |
| battle.gd(バトル連携) | scenes/battle/battle.gd |
| stage_select.gd(選択画面) | scenes/stage_select/stage_select.gd |
| SaveManager(クリア記録) | scripts/autoload/save_manager.gd |
| GameDataRegistry(将来の供給元) | scripts/autoload/game_data_registry.gd |
変更履歴¶
| 日付 | 変更内容 |
|---|---|
| 2026/02/19 | 初版作成(§1 データ構造 / §2 敵行動順 / §3 ステージ選択画面 / §4 バトル連携 / §5 MVP ステージ一覧) |
| 2026/02/20 | MVPステージの最終調整(新規敵ユニット追加等)を§5に反映(Pull Request #122対応) |
| 2026/02/22 | §3 にリニア進行方式(ステージ解放方式)を追記(Issue #250 確定) |