コンテンツにスキップ

ステージシステム設計


§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 配列の順序がそのまま敵の行動順になる。

これは以下の設計判断に基づく:

  1. データの一元管理: 配置位置(grid_index)と行動順(配列内の位置)を同じ構造体で管理することで、「配置されているが行動順に含まれない」「行動順に含まれるが配置されていない」といったデータ不整合を構造的に排除する
  2. レベルデザインの直感性: .tres ファイルで enemy_placements の要素を並べ替えるだけで行動順を変更できる。別途 enemy_action_order 配列を管理する必要がない
  3. 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 確定)