コンテンツにスキップ

バトルシステム設計

スコープ注記: 本ドキュメントはバトルシステムの設計ドキュメントである。 現時点では§1(effect_offsets 座標系ルール)のみを定義している。 ターン進行、ダメージ計算等のバトルルールは v0.2.0 以降で§として追加予定。


§1 effect_offsets 座標系

SkillData.effect_offsets: Array[Vector2i] の座標系ルールを定義する。 スキルの効果範囲をグリッド上で表現するための共通規約であり、TargetResolver が本規約に従ってオフセットを絶対グリッド座標に変換する。


座標系の定義

原点

相対座標方式 — 術者の位置を (0,0) とする。

  • スキル定義が配置位置に依存しない(同じオフセットがどのマスでも同じ意味)
  • 絶対座標方式では「隣接味方を回復」を最大9パターン定義する必要があり非現実的

軸の方向

正方向 定義 根拠
x 前方(敵側) x+ = forward 「前に攻撃する」= x+ が直感的
y 下方(行番号増) y+ = down StageDataindex = y * 3 + x(左上 (0,0))および Godot スクリーン座標系と整合
y 軸
  ↓ (y+)
  ┌──────┬──────┬──────┐
  │(0,0) │(1,0) │(2,0) │  ← 行0(上段)
  ├──────┼──────┼──────┤
  │(0,1) │(1,1) │(2,1) │  ← 行1(中段)  ※ (x,y) 表記
  ├──────┼──────┼──────┤
  │(0,2) │(1,2) │(2,2) │  ← 行2(下段)
  └──────┴──────┴──────┘
     列0     列1     列2
     (前衛)  (中衛)  (後衛)
                           → x+ (forward / 敵方向)

注意: Vector2i(x, y) の順。オフセット Vector2i(1, 0) は「前方1マス」、Vector2i(0, 1) は「下方1マス」。


target_side ごとの基準点

SkillData.target_side によって、オフセットの基準点と解決先グリッドが異なる。

ALLY(味方対象)

項目
基準点 術者の位置
解決先 自軍グリッド
(0,0) の意味 術者自身
例: buffer_01 が (col=1, row=1) に配置、隣接4方向バフ
  offsets = [Vector2i(-1,0), Vector2i(1,0), Vector2i(0,-1), Vector2i(0,1)]

  解決結果(自軍グリッド上の絶対座標):
    (0,1), (2,1), (1,0), (1,2)  ← 上下左右の4マス

ENEMY(敵対象)— 行相対・列固定方式

項目
基準点 (術者と同じ行, 敵前衛列)
解決先 敵軍グリッド
(0,0) の意味 術者と同じ行の、敵前衛(列0)にいる敵
  • x+ は敵陣の奥方向(前衛→中衛→後衛)
  • 術者の列位置は基準点に影響しない(前衛でも後衛でも同じオフセットで同じ敵を狙う)
例: attacker_01 が行1から単体攻撃
  offsets = [Vector2i(0,0)]

  基準点 = (col=0, row=1) ← 敵前衛列・同行
  解決結果 = (0,1) ← 敵グリッドの前衛・行1
例: attacker_03 が行1(中段)から列全体攻撃
  offsets = [Vector2i(0,-1), Vector2i(0,0), Vector2i(0,1)]

  基準点 = (col=0, row=1)
  解決結果 = (0,0), (0,1), (0,2) ← 敵前衛列の全3行

  ※ 行0(上端)に配置した場合:
    基準点 = (col=0, row=0)
    offsets (0,-1) → (0,-1) ← グリッド外 → 無視
    解決結果 = (0,0), (0,1) ← 2体のみヒット
    → 配置位置(行)によって効果範囲が変わる = 配置パズル

ALLY と ENEMY の基準点の違い(まとめ)

target_side 基準点 (0,0) 術者の列位置の影響
ALLY 術者の位置 自分自身 列・行ともに影響する
ENEMY (術者の行, 敵前衛列) 正面の敵前衛 行のみ影響。列は不問

設計根拠:

  • PRD #33 のユースケース記述(「同行の最前列の敵」)と直接対応
  • 列の配置判断は「安全性(被弾リスク)」に一本化され、シンプルな位置パズルを維持
  • スキル定義が術者の列位置に依存しないため、データの可搬性が高い

グリッド境界ルール

1スキル = 1グリッド

1つのスキルは target_side で指定された1つのグリッドのみに作用する。 自軍と敵軍の両方に同時作用するスキルは MVP では存在しない。

将来的に必要になった場合は、スキルに複数の効果エントリを持たせる拡張で対応する。

グリッド外オフセットの処理

解決後の絶対座標がグリッド範囲(0≤x≤2, 0≤y≤2)を超える場合、そのオフセットは 無視(スキップ) する。

  • エラーにしない: グリッド端の配置で効果範囲が自然に狭まる挙動は、配置パズルとして意図的
  • TargetResolver の責務: グリッド外座標を除外し、有効な座標のみを返す

パッシブスキルでの扱い

パッシブスキルもアクティブスキルと同じ座標系・同じ effect_offsets を使用する。

パッシブ種別 offsets 例 target_side 解決タイミング
オーラ型(隣接バフ) [(-1,0), (1,0), (0,-1), (0,1)] ALLY バトル開始時 + 配置変更時
トリガー型(反撃) [] イベント発生時(BattleEngine)
自己バフ型 [(0,0)] ALLY バトル開始時

トリガー型パッシブの特殊扱い

トリガー型パッシブ(例: 被弾時に反撃)の対象は、グリッド位置ではなく イベントコンテキスト(「攻撃してきた敵」)から決定する。

  • effect_offsets は空配列 []
  • TargetResolver は空配列を受けた場合「位置解決不要」として扱う
  • 対象の解決は BattleEngine のイベント処理ロジックが担う

実装ガイドライン

TargetResolver の責務

  1. 術者の位置と target_side から基準点を算出
  2. effect_offsets の各要素を基準点に加算し、絶対グリッド座標を得る
  3. グリッド範囲外の座標を除外
  4. 有効な座標の配列を返す
# 疑似コード
func resolve(caster_pos: Vector2i, offsets: Array[Vector2i],
             target_side: SkillData.TargetSide) -> Array[Vector2i]:
    if offsets.is_empty():
        return []  # トリガー型パッシブ等、位置解決不要

    var origin: Vector2i
    match target_side:
        SkillData.TargetSide.ALLY:
            origin = caster_pos
        SkillData.TargetSide.ENEMY:
            origin = Vector2i(0, caster_pos.y)  # 敵前衛列・同行

    var results: Array[Vector2i] = []
    for offset in offsets:
        var pos := origin + offset
        if _is_in_grid(pos):
            results.append(pos)
    return results

各スキルの具体的なオフセット定義は data/skills/*.tres を参照。自動生成されたユニット一覧でスキルの効果・対象を確認できる。


参照リンク

ドキュメント リンク
スキルシステム PRD #33
バトルシステム PRD #32
SkillData Resource 実装 scripts/data/skill_data.gd
StageData Resource 実装 scripts/data/stage_data.gd
GDD §3 バトルシステム概要 docs/gdd.md
ユニットシステム設計 docs/design/unit_system.md

変更履歴

日付 変更内容
2026/02/17 初版作成(effect_offsets_coordinate.md として)
2026/02/22 battle_system.md にリネーム。§1 として再構成。壊れた参照リンクを修正