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

コーディング規約

本ドキュメントは、コードを書くときに守り続ける規約だけを置く。 なぜその規約があるかは ADR、層の責務と契約は アーキテクチャ方針 を参照。

具体的なフォルダツリー・クラス名・シグネチャは書かない。それはコードが正である。

依存の向き​

トップレベルのディレクトリは5つ。

ディレクトリ役割
core/ゲームの状態と規則。Node を一切含まない
data/.tres によるデータ定義
presentation/シーンと View。Node を含む
app/合成ルート・シーン遷移・セーブIO
dev/開発者モードのオーバーレイ

依存は常に 他の全て → core/ の一方向である。core/ が presentation/ や app/ を参照することは、いかなる理由があっても禁止する。

Autoload は app/ のもの1つだけにする。増やすと、どこからでも状態に触れる経路ができ、契約1 が壊れる。

godot_ai アドオンが登録する _mcp_game_helper は開発支援用であり、ゲームロジックとは無関係である。

core/ の禁止事項​

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

禁止すること理由
Node の継承、SceneTree / get_tree() / Input の参照ヘッドレステストが成立しなくなる(ADR-0011)
await・シグナル演出の待ちが状態層に侵入する(ADR-0012)
randi() / randf() / Array.shuffle()グローバル乱数はセーブで再現できない(ADR-0013)
Intent を経由する以外の状態変更開発者モードの操作も例外ではない(ADR-0014)
型なし変数層をまたぐ誤った参照をエディタが検出できなくなる
子から親への参照RefCounted の相互参照はリークする。必要な文脈は引数で渡す
@toolエディタ実行時に副作用が走る
イベントに演出情報を載せることアニメーション名・色・座標・演出時間は表現層が決める

シャッフルが必要な場合は、状態層が所有する乱数を使って Fisher-Yates を自前で実装する。

命名規約​

対象規約例
ファイル名snake_case.gdbattle_state.gd
クラス名PascalCaseBattleState
Intent〜IntentPlayPageIntent
Event〜EventPagePlayedEvent
定義 Resource〜DefPageDef
実行時インスタンス〜InstancePageInstance
拒否理由StringName の snake_case&"not_enough_ho"

ゲーム用語はドキュメントと同じ語を使う。 toki(刻)・mei(銘)・hokorobi(綻び)・guard(防御)をそのままコード上の名前にし、独自の英訳を発明しない(用語集)。

効果に型を作らない​

「効果1つ = クラス1つ」という対応を作らない(ADR-0035)。効果の単位は作用であり、それは6項を持つデータである(効果システム)。打点が2発あるページは、敵HPへの作用を2つ並べるのであって、2つの効果クラスを持つのではない。

〜Effect は例外にだけ付ける。 作用の文法で表現できない振る舞いが出てきたときに限りクラスを書き、なぜ文法で書けないのかをそのとき記録する。 既定は常に作用の列である。

よく使う作用の組み合わせに名前を付けない。 分類が要るようになってから付ければよく、それはプレイ体験を確かめるまで決められない。先に名前を付けると型の単位になり、そこから仕様の語彙へ逆流する。

コメント​

書くのは、隠れた制約・非自明な不変条件・特定のバグの回避策・読み手が驚く振る舞いがあるときだけである。 コードが何をするか(WHAT)を言い換えるだけのコメントは書かない。

長さは内容が決める。 必要なことが必要な分量だけ書かれていればよく、1行に収めることが目的ではない。説明に3行要るなら3行書く。ただし gdlint の100文字制限はコメントにも掛かるので、長い説明は複数の ## 行に折り返す。短く見せるために1行へ押し込むと、読みにくいコメントと lint 違反の両方を招く。

Issue 番号・受け入れ条件の番号・テストIDをソースコメントに書かない。 これらは Issue が閉じた時点で陳腐化し、コードだけを読む人には辿れない。設計判断の背景・トレードオフ・検討して却下した案は、コミットメッセージ・PR 本文・ADR に置く — そこは変更の経緯を追う場所として残り続ける。

定義と実行時インスタンスを分ける​

.tres は定義である。盤面上の1枚が持つ状態(各面が白紙か・書かれているか・ペンで強化済みか)は、定義とは別のオブジェクトに置く。

.tres から load() したインスタンスを実行時に書き換えてはならない。 Godot の Resource はデフォルトでキャッシュ共有されるため、書き換えると同じ定義を使う全ての札に波及する(ADR-0010)。

Godot 4.7 の罠​

項目注意
レンダラGL Compatibility で動作すること。Forward+ 専用機能を使わない
Resource のキャッシュload() した Resource は共有される(→ 上節)
Array[T] の @export使用可能。ただし型を持たない Array との混在に注意
RefCounted の循環参照相互参照はリークする。親への参照を持たせない
class_name の循環 preloadGDScript は循環 preload に弱い

関連​