メインコンテンツまでスキップ

アーキテクチャ方針

本ドキュメントは層の責務と契約を定義する。この契約は言語にもエンジンにも依存しない。 契約を Godot 上で守るための具体的な規約は コーディング規約、決定の経緯は ADR。 用語の正式な定義は 用語集。

この設計が達成すべきこと​

このプロトタイプは、以下の4つを同時に満たす必要がある。これらは全て「状態と表現の分離」という同じ根から出ている。

要求出典
グラフィック・UI・サウンド・アニメーションを後から差し込めるPRD
戦闘中を含めていつでも中断・再開でき、復帰後に見分けがつかないセーブ/開発者モード
開発者モードから状態を直接操作できる。ただし裏口は作らない同上
ゲームルールをヘッドレスで高速にテストできるテスト方針

層構成​

状態層​

バトル・マップ・ラン全体の状態を保持し、規則に従って変更する。

性質:

  • 画面表示や入力デバイスに関する知識を一切持たない
  • 外部からの変更手段は Intent(意図) のみである。それ以外の変更経路を持たない
  • 状態が変化するたびに、変化の内容を Event として発行する
  • シード付き乱数を自ら所有する。 外部の乱数源を参照しない
  • 任意の時点でまるごと保存でき、保存した値から復元できる

表現層(View)​

状態層が発行するイベントを受け取り、画面表示・音・演出を行う。

性質:

  • イベントだけを購読すれば画面を構築できる。 状態層の内部詳細を知る必要はない
  • イベントの発行と画面上の反映は同期していなくてよい(演出のためにイベントを溜めてから順番に反映してよい)
  • プロトタイプ段階では単純な図形とテキストで表現するが、イベントの受け取り方は本番の資産に差し替えても変わらない

入力層​

マウス・キーボード・タッチ操作を、デバイスに依存しない Intent に変換してから状態層に渡す。

デバイスの違いは入力層と表現層の中に閉じ込め、状態層には影響させない。

開発者モード​

状態層から見れば、開発者モードは入力層と同じ Intent インターフェースを通じて特別な指示を送る、もう一つの発信元である。

通常の入力経路を迂回して状態層を直接改変する裏口は作らない。 デバッグ用の変更も Intent として表現し、状態層の同じ入口を通る。

3つの契約​

契約1:Intent が唯一の入口である​

状態層を変更する方法は、Intent を適用することだけである。

これが保証すること:

保証理由
リプレイが可能Intent 列を記録すれば、同じ状態を再現できる
開発者モードに裏口が不要デバッグ操作も Intent の一種
テストが書きやすいテストは Intent 列を投げて状態を検証するだけ
undo が実装可能状態のスナップショットと Intent 列があれば戻せる

契約2:イベントキュー​

状態層はイベントをキューに積む**。表現層は自分のペースでそれを取り出す。**

シグナルによる即時通知ではなく、順序付きのキューであることが重要である。 シグナルでは「演出を待っている間に状態層が先へ進んでしまう」問題を解けない。

保証理由
演出と状態の分離表現層が3秒かけて演出しても、状態層は既に確定済み
テストでの検証発行されたイベント列をそのまま assert できる
演出スキップキューを一気に消費すれば飛ばせる

イベントは 「何が起きたか」の事実のみを表し、「どう見せるか」を指定しない。

契約3:決定論と乱数​

状態層はシード付き乱数を自ら所有し、その内部状態はセーブに含まれる。

これがないと「保存前と見分けがつかない状態で再開できる」という要求は原理的に達成できない。 デッキのシャッフル、座の移動先の決定、マップの生成、報酬候補の抽選、すべてが乱数に依存している。

保証理由
セーブ/ロードの完全性復帰後の乱数列が保存前と一致する
バグの再現シードを共有すれば同じ状況を再現できる
テストの安定固定シードで決定論的なテストが書ける

グローバルな乱数(randi() など)は状態層で使用してはならない。

観測可能な契約​

  • 表現層は、状態層が発行するイベントだけを購読すれば画面を構築できる
  • イベントの発行と画面上の反映は同期していなくてよい
  • 状態層が保持する値は、任意の時点でまるごと保存でき、保存した値から復元した際、保存前と同一の観測結果(同一のイベント列)が得られる

制約​

  • Godot 4.7 / GL Compatibility レンダラ上で動作すること
  • PC(マウス・キーボード)操作と、将来のタッチ操作の両方が入力層で成立すること
  • 状態層は Godot のシーンツリー(Node)に依存しないこと — これによりヘッドレスでの高速テストが可能になる(ADR-0011)

この方針が禁じること​

以下はバグではなく設計違反として扱う。

  1. 表現層が状態層のオブジェクトを直接書き換えること
  2. 状態層が Node / SceneTree / Input / 画面サイズなどを参照すること
  3. Intent を経由しない状態変更(開発者モードを含む)
  4. 状態層でグローバル乱数を使うこと
  5. イベントに「どう見せるか」の情報(アニメーション名・色・座標など)を含めること

関連​

Implementation Notes​