godot-master について
godot-masterは、Godot 4.7+で開発するアーキテクトや開発者向けのナレッジハブです。アーキテクチャの判断フレームワークや実践ワークフロー、エンジン機能とゲームジャンル別の設計指針を提供し、移行履歴としては扱いません。
主な機能
- 01Godot 4.7+のアーキテクチャ指針
- 02状態の所有権とシグナル設計
- 03状況別のアーキテクチャ判断
- 04プロジェクト構築ワークフロー
- 05システム横断・ジャンル別パターン
活用シーン
- 01Godotプロジェクトの構成を計画
- 02モジュール型エンティティと状態遷移の設計
- 03ゲームジャンルに応じたシステム選択
- 04Godot CLIビルダーを使ったプロジェクト構築
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ thedivergentai/ game-dev-agentic-skills --skill godot-masterインストール後、Claude Code で/godot-masterを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/2d-animation-cutout-and-skeletal.md2d-animation-expert-techniques.md2d-animation-migration-notes.md2d-animation-signals-and-frame-events.md2d-animation.md2d-physics-area2d-and-queries.md2d-physics-collision-layers-masks.md2d-physics-migration-notes.md2d-physics.md3d-lighting-environment-and-fog.md3d-lighting-gi-and-bake-recipes.md3d-lighting-migration-notes.md3d-lighting.md3d-materials-migration-notes.md3d-materials-pbr-workflows.md3d-materials.md3d-world-building-gridmap-and-csg.md3d-world-building-migration-notes.md3d-world-building-streaming-and-procgen.md3d-world-building.mdability-system-elite-ability-patterns.mdability-system-migration-notes.mdability-system.mdadapt-2d-to-3d-migration-notes.mdadapt-2d-to-3d-migration-recipes.mdadapt-2d-to-3d.mdadapt-3d-to-2d-dimension-reduction.mdadapt-3d-to-2d-migration-notes.mdadapt-3d-to-2d.mdadapt-desktop-to-mobile-migration-notes.md詳細
Godot Master:リードアーキテクト向けナレッジハブ
すべてのセクションは、ナレッジの差分、つまりベースモデルがすでに知っていることと、実際の製品を出荷してきたシニア Godot エンジニアが知っていることのギャップに焦点を当てることで、そのトークンに見合う価値を提供します。
ライブラリの対象 — Godot 4.7+
すべてのドメインスキルのミラーは Godot 4.7+(安定版)を対象とします。エンジンのバージョンアップグレード(1.x/2.x のレガシー版 → 3 → 4 → 4.x の段階的アップグレード)には、godot-version-migration を使用してください。このハブを移行履歴として扱わないでください。
各機能へ案内する際に留意すべき 4.7 の横断的な注意事項:AreaLight3D/HDR → 3D ライティング;Asset Store と Asset Library の違い → エクスポート/プラットフォームモジュール;RichTextLabel の ImageUnit、入力デバイス ID 定数、Jolt の挙動 → 移行ハブのモジュールノート。
🧠 パート 1:エキスパートの思考フレームワーク
「誰が何を所有するのか?」 — アーキテクチャの健全性チェック
システムを書く前に、状態の各要素について、次の 3 つの質問に答えてください。
- データを所有するのは誰か?(
CombatSystemではなく、StatsComponentが体力を所有する) - 変更を許可されているのは誰か?(
apply_damage()のような公開メソッドを介して、所有者だけが変更できる) - 変更されたことを知る必要があるのは誰か?(
health_changedシグナルをリッスンしているすべての人)
すべての状態変数についてこの 3 つすべてに答えられない場合、アーキテクチャには結合の問題があります。これは OOP のカプセル化ではありません。Godot 固有の考え方です。なぜなら、アクセス修飾子ではなく、シグナルシステムそのものが強制の仕組みだからです。
Godot の「レイヤーケーキ」
すべての機能を 4 つのレイヤーに整理してください。シグナルは上方向にのみ伝わり、下方向には伝わりません。
┌──────────────────────────────┐
│ PRESENTATION (UI / VFX) │ ← Listens to signals, never owns data
├──────────────────────────────┤
│ LOGIC (State Machines) │ ← Orchestrates transitions, queries data
├──────────────────────────────┤
│ DATA (Resources / .tres) │ ← Single source of truth, serializable
├──────────────────────────────┤
│ INFRASTRUCTURE (Autoloads) │ ← Signal Bus, SaveManager, AudioBus
└──────────────────────────────┘
重要なルール:プレゼンテーションはデータを直接変更してはなりません。インフラストラクチャはシグナルのみを介してやり取りします。Label ノードが player.health -= 1 を呼び出しているなら、アーキテクチャは破綻しています。
シグナルバスの階層型アーキテクチャ
- グローバルバス(Autoload):ライフサイクルイベント(
match_started、player_died、settings_changed)にのみ使用します。デバッグの煩雑化が代償となるため、イベント数は 15 未満に抑えてください。 - スコープ付き機能バス:各機能フォルダーに専用のバスを設けます(例:
CombatBusは戦闘ノード専用)。これが、規模を拡大できる折衷案です。 - 直接シグナル:単一シーン内の親子間の通信に使用します。シーンの境界を越えて使用してはいけません。
🔗 「スマートな相互接続」の指針
エキスパートシステムは、孤立していることではなく、ペイロードの合成によって定義されます。
- 物理演算 → パフォーマンス:
PhysicsServer2DとRenderingServerは、SceneTreeのノードによるオーバーヘッドを回避します。1,000 個以上の弾丸やパーティクルを扱う場合に使用すると、O(1) の処理を実現できます。 - アニメーション → 物理演算:
AnimationTree.get_root_motion_position()は、アニメーションによる変位を物理演算のvelocityに変換し、複雑な移動時の「足滑り」を防ぎます。 - データ → リアクティビティ:シリアライズされた
Resourceオブジェクト(Statsなど)は、変更時にシグナルを発行するため、密結合を避けながら UI を自動的に更新できます。 - アセット → 生成:
ResourceLoaderの非同期フェーズ中にプリロードする O(1) の Dictionary ベースのキャッシュにより、アイテムや敵の生成時に発生する I/O のひっかかりを防ぎます。 - モバイル → ビジュアル:ロード画面中に非表示のエフェクトをインスタンス化して GPU シェーダーパイプラインのコンパイルを強制し、実行時のフレームのひっかかりを防ぎます。
- ネットワーク → 帯域幅:パケットを 100 バイト未満に保つため、同期には JSON/文字列ではなく、
PackedByteArrayへのビットパッキングを使用します。 - ジャンルの合成:
Shooter:100 倍のパフォーマンスを得るため、RayCast3Dノードではなく、必ずintersect_ray()(直接空間状態)を使用します。RPG:エンドゲームの進行を維持するため、ダメージはbase * pow(scaling, level)に従います。RTS:隊形の整合性を保つため、Relative Offsetを使って重心を基準にグループを移動させます。Metroidvania:シームレスなルーム切り替えにはResourceLoader.load_threaded_request()を使用します。Platformer:プロフェッショナルな操作感を実現するには、Jump Buffering(約 0.15 秒)とCoyote Timeが必須です。Simulation:Tick Managerでバッチ処理を行います。数千のユニットを維持するには、エンティティごとの_processを避けてください。Romance:複雑な物語の分岐を表現するため、Multi-Axial Affection(魅力、信頼、安心感)を使用します。Architecture:シーン間の循環結合をなくすため、Signal Architectureは「シグナルは上へ、呼び出しは下へ」という原則に厳密に従います。
🧭 パート 2:アーキテクチャ上の意思決定フレームワーク
マスター意思決定マトリクス
| シナリオ | 戦略 | 必須スキルチェーン | トレードオフ |
|---|---|---|---|
| 迅速なプロトタイプ | イベント駆動型モノリス | 読む:基礎 → オートロード。ジャンルやプラットフォームのリファレンスは読み込まないでください。 | すぐに着手できますが、スパゲッティ化のリスクがあります |
| 複雑なRPG | コンポーネント駆動型 | 読む:コンポジション → 状態 → RPGステータス。マルチプレイヤーやプラットフォームのリファレンスは読み込まないでください。 | 初期設定は大変ですが、無限に拡張できます |
| 大規模なオープンワールド | リソースストリーミング | 読む:オープンワールド → セーブ/ロード。パフォーマンスも読み込みます。 | I/Oが複雑で、10Kユニットを超えると浮動小数点精度による揺れが発生します |
| サーバー認証型マルチプレイヤー | 決定論的 | 読む:サーバーアーキテクチャ → マルチプレイヤーネットワーク。シングルプレイヤー向けジャンルのリファレンスは読み込まないでください。 | レイテンシーが高くなりますが、チート対策を強化できます |
| モバイル/Webへの移植 | アダプティブ・レスポンシブ | 読む:UIコンテナー → デスクトップからモバイルへの適応 → モバイルプラットフォーム。 | UIは複雑になりますが、幅広いユーザーに届けられます |
| アプリケーション/ツール | アプリコンポジション | 読む:アプリコンポジション → テーマ設定。ゲーム固有のリファレンスは読み込まないでください。 | ゲームとは異なるパラダイムです |
| 恋愛/恋愛シミュレーション | 好感度の経済設計 | 読む:恋愛 → 会話 → UIリッチテキスト。 | UI/ナラティブの密度が高くなります |
| 秘密/イースターエッグ | 意図的な難読化 | 読む:秘密 → 永続化。 | コミュニティの活性化につながりますが、デバッグのリスクがあります |
| 収集クエスト | 探索者ロジック | 読む:収集要素 → Marker3Dの配置。 | プレイヤーの定着と探索意欲につながります |
| 季節イベント | 実行時の差し込み | 読む:イースターのテーマ設定 → マテリアルの切り替え。 | すばやくブランドを反映でき、アセットを汚しません |
| ソウルライクの死と復活 | リスクと報酬を伴う復活 | 読む:復活/遺体回収 → 3D物理。 | 緊張感を高められますが、プレイヤーを苛立たせるリスクがあります |
| ウェーブ制アクション | 戦闘ペーシングループ | 読む:ウェーブ → 戦闘。 | 緊張感を高め、遭遇を設計できます |
| バランス/難易度/経済のペーシング | モンテカルロ・バランスラボ | 読む:リソース → 経済 → 戦闘/RPGステータス/ウェーブ(必要に応じて) → モンテカルロ・バランサー → テスト → ビルダー。 | 統計的な厳密さを得られます。抽象シミュレーションはヘッドレスGodotと照らし合わせて調整する必要があります |
| サバイバル経済 | 採集ループ | 読む:採集 → インベントリ。 | リソースの希少性とループの継続性を実現します |
| レース/スピードラン | 検証ループ | 読む:タイムトライアル → 入力バッファ → レースジャンル。 | 高い精度を実現し、ゴースト記録がプレイ意欲を高めます |
| ホラー/ステルス | 緊張感の管理 | 読む:ホラージャンル → ステルスジャンル → オーディオ。 | 雰囲気を作り、プレイヤーの無防備さを演出します |
| カード/ボードゲーム | ルールの適用 | 読む:カードゲームジャンル → ターンシステム。 | 状態が決定論的になる一方、UIの比重が大きくなります |
| シミュレーション/RTS | バッチ処理 | 読む:シミュレーションジャンル → RTSジャンル → パフォーマンス。 | 大量のユニットに対応し、O(1)のロジックを実現します |
| HDR/シネマティックなビジュアル | ディスプレイパイプライン | 読む:3Dライティング → デスクトッププラットフォーム → シェーダーの基礎。プロジェクト設定でビューポートHDRを有効にします。 | プラットフォームごとのトーンマッピング調整が必要です |
| 長方形のエリアライト | AreaLight3D | 読む:3Dライティング → 3Dマテリアル。発光+GIのハックよりAreaLight3Dを優先します。 | 最高品質で使用するにはForward+レンダラーが必要です |
| モバイルのタッチ操作 | ネイティブジョイスティック | 読む:モバイルプラットフォーム → デスクトップからモバイルへの適応。組み込みの仮想ジョイスティック(4.7+)を使用します。 | プラグインへの依存を抑えられます |
| アドオン/アセットの検索 | アセットストア | 読む:プロジェクトの基礎 → ビルドのエクスポート。アセットストアがアセットライブラリに代わります。 | ストアのUIはベータ版のため、アドオンごとにライセンスを確認してください |
| エージェントの視覚確認/ビジュアルQA | キャプチャ → WebP → 評価基準 | 読む:エージェントの視覚機能。スクリーンショットのアセット、ウィンドウ/領域/画面、または一時的なエディターブリッジを使って、構造化レビューを行います。ジャンルのリファレンスは読み込まないでください。 | ホスト側のみで使用し、オートロードにしないでください/ステージングしたアドオンを残さないでください |
| アーティファクト → Godotプロジェクト | 台帳の後にスタブ | 読む:GDAS-reader → REA。スタブで指定されるまでは、ジャンルのリファレンスを読み込まないでください。 | スタブのみを作成し、不明な動作はpassのままにします |
「ノードを使わない」判断
専門家だけが行う、最も影響の大きい判断のひとつです。Godot のドキュメントでは、「あらゆるものにノードを使うのは避ける」よう明確に示されています。
| 種類 | 使用する場面 | コスト | 専門家向けのユースケース |
|---|---|---|---|
Object | カスタムデータ構造、手動のメモリ管理 | 最軽量です。.free() を手動で呼び出す必要があります。 | カスタム空間ハッシュマップ、ECS のようなデータストア |
RefCounted | 一時的なデータパケット、自動削除されるロジックオブジェクト | 参照がなくなると自動的に削除されます。 | DamageRequest、PathQuery、AbilityEffect — シーンツリーを必要としないロジックパケット |
Resource | Inspector に対応したシリアライズ可能なデータ | RefCounted より少し重くなります。.tres の入出力を処理します。 | ItemData、EnemyStats、DialogueLine — デザイナーが Inspector で編集するデータ全般 |
Node | _process/_physics_process が必要、シーンツリー内に存在する必要がある | 最も重くなります — ノードごとに SceneTree のオーバーヘッドが発生します。 | フレームごとの更新や空間トランスフォームが必要なエンティティのみに使用します |
専門家向けのパターン:すべてのロジックパケットとデータコンテナに RefCounted のサブクラスを使用します。空間ツリー内に存在する必要があるものだけに Node を使用します。これにより、複雑なシステムのシーンツリーのオーバーヘッドを半減できます。
🔧 パート 3:コアワークフロー
ワークフロー 1:プロフェッショナルなスキャフォールディング
空のプロジェクトから、本番環境に対応したコンテナまで。
必須 — ファイル全体を読むこと:基礎
- クラスの種類別ではなく、機能別(
/features/player/、/features/combat/)に整理します。player/フォルダーには、プレイヤー用のシーン、スクリプト、リソース、テストをまとめます。 - 読むこと:シグナルアーキテクチャ — イベント数を 15 未満に抑えた
GlobalSignalBusオートロードを作成します。 - 読むこと:GDScript の習得 — Project Settings → GDScript → Debugging で
untyped_declaration警告を有効にします。 - ベースとなる
.gitignore、エクスポートプリセット、入力マップには、**プロジェクトテンプレート**を適用します。 - Godot CLI 経由でシーン階層をプログラムから生成するには、Builder(
builder_create_scene.py、builder_add_node.py、builder_save_scene.py)を使用します。
注意
ワークフロー 1 で絶対にしないこと
- 絶対にロジックスクリプトで
res://パスを使用しないでください。リソースを移動しても有効な状態を保てるよう、@export_fileまたは@export_dirを使用してください。- 絶対に
_init()で子ノードを初期化しないでください。シーンツリーの準備ができていません。_ready()または@onreadyを使用してください。- 絶対に
Physics Ticksのプロジェクト設定を「Default」のままにしないでください。一貫性を保つには 60 に設定するか、適応型ロジックにはEngine.physics_ticks_per_secondを使用してください。- デバッグに 絶対に
_process()内でprint()を使用しないでください。フレーム時間の急増を避けるため、Debuggerまたはpush_error()を使用してください。
スキャフォールディング中は、戦闘、マルチプレイヤー、ジャンル、プラットフォームのリファレンスを読み込まないでください。
ワークフロー 2:エンティティのオーケストレーション
モジュール化され、テスト可能なキャラクターを構築します。
必須の順序 — すべて読むこと:Composition → State Machine → CharacterBody2D または Physics 3D → Animation Tree エンティティの作業では、UI、Audio、Save/Load のリファレンスを読み込まないでください。
- ステートマシンは
InputComponentに問い合わせます。入力を直接処理することはありません。これにより、リファクタリングなしで AI とプレイヤーを切り替えられます。 - ステートマシンが処理するのは遷移のみです。ロジックはコンポーネントに配置します。
MoveStateがMoveComponentに動作するよう指示し、その逆にはしません。 - すべてのエンティティはF6 テストに合格する必要があります。「現在のシーンを実行」(F6)を押してもクラッシュしないことを確認してください。クラッシュする場合、そのエンティティにはシーン外部の依存関係があります。
注意
ワークフロー 2 で絶対にしてはいけないこと
- 絶対に
parent.do_thing()を呼び出さないでください。親が変更されると、エンティティが壊れます。代わりにシグナルrequest_actionを発行してください。- 絶対に移動に
_processを使用しないでください。可変リフレッシュレートのモニターでのちらつきを避けるため、_physics_processを使用してください。- 絶対にアニメーション名をハードコードしないでください。
AnimationPlayerで簡単に名前を変更できるよう、StringName定数またはResourceマップを使用してください。- 絶対に絶対パスで
get_node()を使用しないでください。ツリーのリファクタリングに耐えられるよう%UniqueNameを使用してください。
ワークフロー 3:データ駆動型システム
リソースを介して Combat、Inventory、Stats を連携させます。
必須の順序 — すべて読むこと:Resource Patterns → RPG Stats → Combat → Inventory
Resourceを継承するItemData.gdを 1 つ作成します。スクリプトを 100 個作る代わりに、これを 100 個の.tresファイルとしてインスタンス化します。- HUD は Player を直接参照しません。Signal Bus 上の
player_health_changedをリッスンします。 - すべての
@export Resource変数で「Local to Scene」を有効にするか、_ready()でresource.duplicate()を呼び出してください。これを怠ると、Part 8 の Bug #1 の原因になります。
注意
ワークフロー 3 で絶対にしてはいけないこと
- 絶対にSignal Bus で
Nodeの参照を渡さないでください。オブジェクトは解放されるため、長期的な追跡には RID または ID のほうが安全です。- 絶対に実行時にコードから
.tresファイルを変更しないでください(ディスク上のファイルが変更されます)。変更前に必ず.duplicate()を使用してください。- 絶対に検索頻度の高い処理に
Arrayを使用しないでください。O(1) で検索できるStringNameキーのDictionaryを使用してください。- 絶対にアイテム数や正確なリソース管理に
floatを使用しないでください。intを使用し、表示用にスケーリングしてください。
ワークフロー 4:永続化パイプライン
必須:Autoload Architecture → Save/Load → Scene Management
- Dictionary マッピングを使用してシリアライズします。新しいフィールドを追加しても古いセーブファイルが壊れないよう、
.get("key", default_value)を使用してください。 - プロシージャルワールドでは、マップ全体ではなく Seed と変更内容の Delta-List を保存します。100MB のワールドを 50KB のセーブデータにできます。
注意
ワークフロー 4 で絶対にしてはいけないこと
- 絶対に
ObjectやNodeのインスタンス全体を保存しないでください。一時的なポインターが含まれています。データをDictionaryまたはカスタムResourceに抽出してください。- 厳密な型付けが必要なデータ(例:
Vector2)に 絶対にJSONを使用しないでください。構造化された Godot 型にはvar_to_bytesまたはConfigFileを使用してください。- オートセーブのためにメインスレッドを絶対にブロックしないでください。大きな Dictionary のシリアライズには
ThreadまたはWorkerThreadPoolを使用してください。- エクスポート済みプロジェクトで
res://に絶対に保存しないでください。永続データには必ずuser://を使用してください。
ワークフロー 5:パフォーマンスの最適化
必須:デバッグ/プロファイリング → パフォーマンスの最適化
診断を優先するアプローチ(決して闇雲に最適化しないでください):
- スクリプトの処理時間が長い → 組み込みの Profiler でプロファイリングします。何百ものノードで
_processが呼び出されていないか確認します。単一マネージャーパターンまたは Server API に切り替えます(Part 6 を参照)。 - ドローコールが多い → 繰り返しのジオメトリには
MultiMeshInstanceを使用します。ORM テクスチャでマテリアルをバッチ化します。 - 物理演算によるカクつき → コリジョンをプリミティブ形状に簡略化します。2D Physics または 3D Physics を読み込みます。移動処理に
_physics_processではなく_processを使用していないか確認します。 - VRAM の過剰使用 → テクスチャを VRAM 圧縮に切り替えます(デスクトップでは BPTC/S3TC、モバイルでは ETC2)。PNG を未圧縮のまま出荷してはいけません。
- 断続的なフレームスパイク → 通常は GC パス、同期的な
load()、または NavigationServer の再計算が原因です。ResourceLoader.load_threaded_request()を使用します。
注意
ワークフロー 5 の禁止事項
- 決して
_process内でget_nodes_in_group()を使用しないでください。毎フレーム O(n) の処理が発生します。配列を_ready()でキャッシュしてください。- 決して「Stay」ロジックに
Area2Dシグナルを使用しないでください。定期的にget_overlapping_bodies()を呼び出すか、マネージャーレベルでPhysicsServerのチェックを使用してください。- 決してプロファイリングの前に最適化しないでください。ドローコールが 2000 回あり GPU の処理を妨げているなら、スクリプトの 1ms は問題ではありません。
- ホットパスでは決して
load()を使用しないでください。必ずpreloadを使用するか、非同期読み込みにはResourceLoaderを使用してください。
ワークフロー 6:クロスプラットフォーム対応
必須:入力処理 → デスクトップからモバイルへの対応 → モバイルプラットフォーム 必要に応じて以下も読む:デスクトッププラットフォーム、Web プラットフォーム、コンソールプラットフォーム、VR プラットフォーム。
- すべての入力タイプを正規化されたアクションに変換する
InputManagerオートロードを使用します。Input.is_key_pressed()を直接読み取ってはいけません。コントローラーとタッチに対応できなくなります。 - モバイルのタッチターゲット:物理サイズで最低 44px にします。ノッチや切り欠きのあるデバイスでは、Safe Area のロジックとともに
MarginContainerを使用します。 - Web エクスポート:Godot の
AudioServerは最初の再生前にユーザー操作を必要とします(ブラウザーのポリシーによる制約です)。「クリックして開始」画面で対応します。
注意
ワークフロー 6 の禁止事項
- 決して機能の検出に
OS.get_name()を使用しないでください。「SteamDeck」のようなサブセットに対応するには、OS.has_feature("mobile")またはカスタム機能タグを使用します。- 決して特定のアスペクト比を前提にしないでください。必ず
Anchorノードと組み合わせてExpandまたはKeep Aspectを使用します。- 決してGLES3/Compatibility の代替パスなしで、デスクトップ専用シェーダー(複雑な深度サンプリングなど)をモバイル/Web で使用しないでください。
- デスクトップビルドで
physical_keycodeを無視してはいけません。これにより、キーボード配列(AZERTY/QWERTY)が移動操作に影響しないようにできます。
- サニタイズされていない文字列を決して
JavaScriptBridge.eval()に渡さないでください。これにより、Web ビルドでのスクリプトインジェクションを防げます。sanitize_js_string()ヘルパーを使用してください。
ワークフロー 7:プロシージャル生成
必須:プロシージャル生成 → タイルマップを極める または 3D ワールド構築 → ナビゲーション
- 決定論的な生成を行うため、固定の
seedを設定したFastNoiseLiteリソースを必ず使用してください。 - メインスレッドで NavMesh をベイクしないでください。
NavigationServer3D.parse_source_geometry_data()とNavigationServer3D.bake_from_source_geometry_data_async()を使用してください。 - 無限ワールドでは、チャンクの読み込みは必ず
WorkerThreadPoolを使用してバックグラウンドスレッドで行ってください。シーンのチャンクをツリー外で構築し、メインスレッドでadd_child.call_deferred()を呼び出してください。
注意
ワークフロー 7:絶対にしてはいけないこと
- 「背景」のノイズに対して、ノードを絶対にインスタンス化しないでください。数千個の小さなディテールには、
MultiMeshInstanceまたは_draw内の描画ループを使用してください。- 1つの変更のためにマップ全体を絶対に再生成しないでください。実際に変更された部分だけを更新する「ダーティチャンク」システムを使用してください。
concave_polygon_shapeを使用する場合、メッシュ生成と同じフレームにコリジョンを絶対に配置しないでください。物理スレッドが停止します。- すべてのユニットについて、パス検索を毎フレーム絶対に実行しないでください。
target_positionをタイマーで更新するNavigationAgentを使用してください。
ワークフロー 8:マルチプレイヤーアーキテクチャ
必須 — 読んでください:シングルプレイヤーからマルチプレイヤーへ → ネットワーキング → サーバーアーキテクチャ シングルプレイヤーのジャンル別ブループリントは読み込まないでください。
- クライアントは入力を送り、サーバーは結果を計算します。クライアントがダメージ、位置の差分、インベントリの変更を決定することは絶対にありません。
- サーバーによる再同期を伴うクライアントサイド予測を使用してください。ローカルで予測し、サーバーのスナップショットに基づいて修正します。最大約 150ms のレイテンシを隠蔽できます。
- Godot 4 では、
MultiplayerSpawnerがレプリケーションを処理します。グローバルではなく、シーンごとに設定してください。
注意
ワークフロー 8:絶対にしてはいけないこと
- 検証せずに
rpc_id(1, ...)(クライアントからサーバー)を絶対に信頼しないでください。ハッキングされたクライアントはdamage = 999999を送信できます。_processのトランスフォームを直接絶対にレプリケーションしないでください。Inputベクトルをレプリケーションし、両側で移動をシミュレートしてください。- 高頻度パケット(移動)に
TCPを絶対に使用しないでください。UDP/ENetを使用し、補間でパケットの損失に対処してください。- すべての投射物を絶対に同期しないでください。ビジュアルにはクライアントサイド予測を使用し、「発射」イベントのみを RPC で送信してください。
ReflectionProbe、VoxelGI、SDFGIの比較:プローブは低コスト/静的、VoxelGI は中程度のコスト/ベイク済み、SDFGI は高コスト/動的です。プラットフォームの予算に応じて選択してください(パート 5 を参照)。
ワークフロー 9:レスポンシブ UI とエキスパート向けテーマ設定(監査済み)
必須チェーン:UI コンテナー → UI テーマ設定 → リッチテキスト → トゥイーン
- F6 の原則:すべての UI シーンは単独でテストできる必要があります。
MOUSE_FILTER_STOPは背景にのみ使用し、子要素にはPASSを使用してください。 - ゆとりの確保:手動で余白を設定する代わりに、
add_theme_constant_override("separation", X)を使用してください。 - 適応型スケーリング:ブレークポイントに応じたモバイル/デスクトップの切り替えには、
ui_containers_responsive_layout_builder.gdを使用してください。 - ライフサイクルの安全性:新しい子要素へ同じフレーム内でスクロールしないでください。
scroll_verticalを変更する前に、await get_tree().process_frameを実行してください。 - データ統合:
Resource-to-UIバインディングを使用してください。UI ノードはステートレスな投影レイヤーでなければなりません。
注意
ワークフロー 9 の禁止事項
- 絶対に絶対ピクセルオフセットを使用しないでください。4K ディスプレイや小型のモバイル画面では UI が読めなくなります。
Containerのサイズ設定を使用してください。- 絶対に
MarginContainersを深くネストしないでください。インスペクターが使いづらくなります。プロジェクト全体の余白には、単一のThemeリソースを使用してください。- 絶対にUI ボタンをゲームプレイロジックに直接接続しないでください。UI は「シグナル」を送信し、
PlayerControllerが受信します。これにより、UI 削除時のクラッシュを防げます。- 絶対に
_process()を使って UI 要素をターゲットへ移動させないでください。カクつきやフレームレートへの依存を避けるため、Tweenを使用してください。- 絶対に透明なコンテナーの
mouse_filterをSTOPのままにしないでください。背後にあるすべての要素へのクリックを「奪って」しまいます。
- 絶対に
res://プレフィックスと安全な拡張子(.tres、.res、.theme)を検証せずに、パスに対して動的なload()を使用しないでください。任意のコードやリソースの実行を防ぎます。
ワークフロー 10:シネマティックなライティングと VFX(監査済み)
必須チェーン:3D ライティング → パーティクル → 3D マテリアル → シェーダー
- GI の選択:屋内には VoxelGI、オープンワールドには SDFGI を使用してください。両方の範囲が重なる状態でリリースしないでください。
- シャドウの予算:シャドウを投影する DirectionalLight は最大 2 つまでにしてください。モバイル向けの補助光には
3d_lighting_fake_gi_bounce.gdを使用してください。 - VFX のライフサイクル:タイマーより
finishedシグナルを使用してください。非同期 GPU の停止を避けるため、restart()で再実行してください。 - 最適化:GPU キャッシュとテクスチャスロットを節約するため、
ORM Textureパッキング(AO/ラフネス/メタル)を使用してください。 - バッチ処理:ドローコールのペナルティなしに何千ものインスタンスでマテリアルを変化させるには、
Instance Uniformsを使用してください。
注意
ワークフロー 10 の禁止事項
- 絶対に
CollisionShapeノードをスケーリングしないでください。物理演算のジッターを避けるため、Shape Resource のみを厳密にスケーリングしてください。- 絶対に切り抜きメッシュ(葉やフェンス)に
TRANSPARENCY_ALPHAを使用しないでください。ソートの乱れを防ぐため、ALPHA_SCISSORを使用してください。- 絶対にゲームプレイ中に CSG ノードをアニメーションさせないでください。CPU による高コストなジオメトリの再計算が発生します。
- 絶対に2D 風のゲームにリアルタイムのグローバルイルミネーション(SDFGI/VoxelGI)を使用しないでください。
DirectionalLight2DとCanvasModulateを使用してください。- 絶対に
Camera3Dのニア/ファー平面を無視しないでください。不適切な設定は広大なワールドで Z ファイティングを引き起こします。
ワークフロー 11:プログラムによるシーン構築(ビルダー)
必須:ビルダー
バッチ処理または複雑な手続き型の足場構築にのみ使用してください。 大規模な CLI 自動化を行う場合は、単独の godot-builder スキルを優先してください。
- ステップ 1:ディスクに触れる前に、ノード階層を紙または Markdown に書き出します。
- ステップ 2:
builder_create_scene.pyを使用して、ルートノードと.tscnのパスを定義します。 - ステップ 3:子ノードには
builder_add_node.pyを使用します。シリアライズで保持されるよう、すべてのノードにownerを設定します。 - ステップ 4:シーンが問題なく読み込まれることを確認するため、必ず
builder_run_project.pyまたはbuilder_launch_editor.pyを呼び出します。 - エキスパートルール:Builder は構造(ノード、名前、継承)の構築に使用し、振る舞いの構築には GDScript を使用します。
注意
ワークフロー 11:絶対にしてはいけないこと
- 絶対に、階層を設計せずにいきなり
builder_add_node.pyを実行しないでください。スパゲッティ状のシーンができてしまいます。- 絶対に、スクリプトやシーンのプロパティで絶対ファイルシステムパスを使用しないでください。
res://のみを使用してください。- 絶対に、Shape リソースを割り当てずに
CollisionShape2D/CollisionShape3Dを追加しないでください。ノードを追加するだけでは何も起こりません。- バッチでシーンを書き込んだ後、
builder_run_project.py/builder_launch_editor.pyによる検証を絶対に省略しないでください。
セキュリティ:境界マーカーと検証
エージェントがファイルを書き込む前に、信頼できないシーン/データテキストを取り込む場合:
- 境界マーカー:
<<<CONTEXT_START>>>と<<<CONTEXT_END>>>で分析内容を囲みます。 - サニタイズ:ノード名は英数字またはアンダースコアのみで構成する必要があります。パスは
res://で始まる必要があります。 - 検証:変更前にシーンの存在を確認します。
🚫 パート 4:エキスパートが絶対にしてはいけないこと
各ルールには、一見わかりにくい理由、つまり実際のリリース経験を通じて初めて学べることが含まれています。
- 決して
get_tree().root.get_node("...")を使用しないでください — 絶対パスは、祖先ノードの名前変更や親の変更が一度でもあると機能しなくなります。%UniqueNames、@export NodePath、またはシグナルベースの検出を使用してください。 - ループ内や
_process内で決してload()を使用しないでください — 同期的なディスク読み込みは、メインスレッド全体をブロックします。小さなアセットにはスクリプトの先頭でpreload()を、大きなアセットにはResourceLoader.load_threaded_request()を使用してください。 - 外部参照が存在する間は決して
queue_free()を実行しないでください — 参照を保持している親ノードや配列は、「Deleted Object」エラーを引き起こします。_exit_tree()で参照をクリーンアップし、解放する前にnullを設定してください。 - ゲームプレイのロジックを決して
_draw()に記述しないでください —_draw()はレンダリングスレッドで呼び出されます。ゲーム状態を変更すると、_physics_processとの競合状態が発生します。 - 1000 個以上のオブジェクトが重なり合う場合、決して
Area2Dを使用しないでください — 各オーバーラップチェックには O(n²) のブロードフェーズコストがかかります。弾幕パターンにはShapeCast2D、PhysicsDirectSpaceState2D.intersect_shape()、またはサーバー API を使用してください。 - コンポーネントから外部状態を決して変更しないでください —
HealthComponentが$HUD.update_bar()を呼び出す場合、HUD を削除するとゲームがクラッシュします。コンポーネントはシグナルを発行し、リスナーが応答方法を決定します。 _physics_process内で決してawaitを使用しないでください —awaitは実行を一時停止するため、物理ステップでフレームがスキップされます。シグナルをトリガーとして、非同期処理を別のメソッドに移してください。- 頻繁に実行される辞書の検索で
Stringキーを決して使用しないでください — String のハッシュ化には O(n) かかります。O(1) のポインター比較ができるStringName(&"key")または整数の列挙型を使用してください。 - 解放済みオブジェクトへの
Callable参照を決して保持しないでください — クラッシュが無言で発生したり、エラーがスローされたりします。_exit_tree()でシグナルを切断するか、CONNECT_ONE_SHOTを使用してください。 - 1000 個以上のエンティティに
_processを決して使用しないでください —_processの呼び出しごとに、ノード単位の SceneTree オーバーヘッドが発生します。データ構造体の配列を反復処理する単一のManager._process(データ指向パターン)を使用するか、サーバー API を直接使用してください。 - 解放される可能性があるノードで決して
Tweenを使用しないでください — Tween の実行中にノードがqueue_free()されると、エラーが発生します。_exit_tree()で Tween を停止するか、SceneTree にバインドしてください:get_tree().create_tween()。 _process内でRenderingServerやPhysicsServerにデータを要求しないでください — これらのサーバーは非同期で動作します。ゲッター関数を呼び出すと同期的な停止が発生し、パフォーマンスが大幅に低下します。これらの API は、頻繁に実行される処理で意図的に書き込み専用として設計されています。- 初期化順序のバグを取り繕うために
call_deferred()を決して使用しないでください — アーキテクチャ上の問題(ツリー順序への依存)を隠してしまいます。明示的な初期化シグナルまたは@onreadyを使って、実際の依存関係を解決してください。 - 循環するシグナル接続を決して作成しないでください — ノード A が B に接続し、B が A に接続する状態です。最初のシグナル発行時に無限ループが発生します。メディエーターパターン(シグナルバス)を使って循環を断ち切ってください。
- 継承を決して 3 階層より深くしないでください — 3 階層を超えると、
super()の呼び出しチェーンのデバッグが非常に困難になります。代わりにコンポジション(子Node)を使って動作を追加してください。 - 物理演算が多いジャンル(FPS/ARPG)では、ヒット判定や移動に決して
_processを使用しないでください。フレームレートに左右されない衝突判定を実現するため、必ず_physics_processを使用してください。 - 永続的なゲーム状態(Health、XP、Inventory)について、クライアントを権威のある情報源として決して信頼しないでください。Server-Auth または Secure Checksums のみで処理してください。
- 実行時に高頻度で行うチェックには、標準の文字列を決して使用しないでください。O(n) のハッシュ化を避けるため、必ず
StringName(&"active")を使用してください。 - ユニット数の多いゲーム(RTS/MOBA)で、RVO の回避処理を毎フレーム手動で行わないでください。
NavigationAgentの内部スレッド処理に任せてください。 - プロシージャル生成や重い I/O のために、メインスレッドを決してブロックしないでください。必ず
WorkerThreadPoolに処理を委譲してください。 - 固有のインスタンスで使用するリソース(例:敵のステータス)では、
Local-to-Sceneを決して無効にしないでください。無効にすると、すべてのインスタンス間で共有メモリのバグが発生します。 - 通貨に
floatを決して使用しないでください。複雑な経済システムでの精度のずれを防ぐため、必ず整数のセント単位を使用してください。 physics_frameより前にtarget_positionを決して設定しないでください。ナビゲーションマップは_ready()中には準備できていません。- 大きな切り抜きサーフェス(葉など)に
TRANSPARENCY_HASHやALPHAを決して使用しないでください。パフォーマンスとソートのため、ALPHA_SCISSORを使用してください。 CollisionShapeノードを決してスケーリングしないでください(Node2D/3D のスケール)。予測できない物理法線やジッターを避けるため、シェイプハンドルを使用するか、リソースのサイズを変更してください。is_on_floor()が true のときに重力を決して適用しないでください。微小なジッターが発生し、床へのスナップが妨げられます。垂直速度を必ず 0 または小さな定数にリセットしてください。- 動的シグナル(キャプチャするラムダ)の切断を決して忘れないでください。Godot はローカル変数をキャプチャするラムダを自動で切断できないため、解放済みオブジェクトでクラッシュが発生します。
- モバイルのタッチ操作にマウスイベントを決して使用しないでください。信頼性の高いマルチタッチ対応のため、必ず
InputEventScreenTouchとInputEventScreenDragを使用してください。 - モバイルで Forward+ レンダラーを決して使用しないでください。GPU のボトルネックやバッテリー消費を避けるため、必ず Mobile または Compatibility レンダラーを使用してください。
- マウスの回転量を Transform に直接決して加算しないでください。ジンバルロックや精度の低下を防ぐため、Yaw/Pitch の変数を別々に保持してください。
- 実行時に高頻度で行うチェックに標準の String を決して使用しないでください。O(n) のハッシュ化オーバーヘッドを避けるため、必ず
StringName(&"active")を使用してください。 - ゲーム状態(Health、Inventory)についてクライアントを決して信頼しないでください。クライアントはアクションを提案し、サーバーが検証してブロードキャストすることで、不正行為を防ぎます。
- 移動の更新に
ReliableRPC を決して使用しないでください。高レイテンシー環境での Head-of-Line ブロッキングを防ぐため、UnreliableOrderedを使用してください。
📊 パート 5:パフォーマンス予算(具体的な数値)
| 指標 | モバイルの目標 | デスクトップの目標 | 専門家向けメモ |
|---|---|---|---|
| ドローコール数 | < 100(2D)、< 200(3D) | < 500 | 植生や破片には MultiMeshInstance を使用します |
| 三角形数 | 表示中は < 100K | 表示中は < 1M | 500K を超える場合は LOD システムが必須です |
| テクスチャ VRAM | < 512MB | < 2GB | VRAM 圧縮:ETC2(モバイル)、BPTC(デスクトップ) |
| スクリプト実行時間 | フレームあたり < 4ms | フレームあたり < 8ms | ホットループを Server API に移動します |
| 物理ボディ数 | アクティブなものが < 200 | アクティブなものが < 1000 | 大量シミュレーションには PhysicsServer の直接 API を使用します |
| パーティクル数 | 合計 < 2000 | 合計 < 10000 | GPU パーティクルを使用し、visibility_aabb を手動で設定します |
| オーディオバス数 | 同時に < 8 | 同時に < 32 | オーディオシステムのバスルーティングを使用します |
| セーブファイルサイズ | < 1MB | < 50MB | プロシージャルワールドにはシード + 差分パターンを使用します |
| シーンの読み込み時間 | < 500ms | < 2s | ResourceLoader.load_threaded_request() |
⚙️ パート 6:Server API — 専門家向けのパフォーマンス向上策
これは、ほとんどの Godot 開発者が学ぶことのない知識です。シーンツリーがボトルネックになったら、Godot の低レベル Server API を使ってシーンツリーを完全に回避します。
Server API に切り替えるタイミング
- 10K 以上の描画インスタンス(スプライト、メッシュ):
Sprite2D/MeshInstance3Dノードの代わりに、RID を使ってRenderingServerを使用します。 - スクリプトからの操作を伴う弾幕系/パーティクルシステム:
Area2Dノードの代わりに、PhysicsServer2Dでボディを作成します。 - 大量の物理シミュレーション:ラグドール群、破片、または流体のようなシミュレーションには、
PhysicsServer3Dを直接使用します。
📊 パフォーマンス比較:SceneTree と Server API
SceneTree を回避すると、ノードのライフサイクル管理、シグナルの伝播、仮想関数(_process など)の呼び出しに伴う大きな CPU オーバーヘッドを排除できます。
| 指標 | SceneTree(ノード) | Server API(RID) | 専門家向けの理由 |
|---|---|---|---|
| オブジェクト数の上限 | 約 1,000~5,000 | 50,000 以上 | SceneTree の走査コストは O(n) です。サーバーでは O(1) の RID による直接ハンドルを使用します。 |
| メモリオーバーヘッド | ノードあたり約 2KB~10KB | RID あたり < 200 bytes | ノードはツリーの状態、シグナル、インスペクターのメタデータを保持します。RID は不透明な 24 バイトのハンドルです。 |
| CPU 時間 | 高い(仮想関数呼び出し) | 最小(直接 API) | ノードではインスタンスごとに _process を呼び出す必要があります。サーバーは C++ で操作をまとめて処理します。 |
| スレッド処理 | メインスレッドのみ | 本質的にスレッドセーフ | ほとんどの Server API はスレッドセーフです(Project Settings で有効にする必要があります)。 |
| ガベージコレクション | 自動(RefCounted) | 手動(割り当て/解放) | サーバーでは手動のライフサイクル管理(RID の作成/削除)が必要です。 |
専門家向けメモ:RID を使うと、未加工のデータを管理し、エンジンのコアロジックと直接やり取りできます。SceneTree の管理処理がボトルネックとなる弾幕系、大量の植生、複雑なプロシージャルシミュレーションにおいて、これは主な「切り札」となります。
RID パターン(専門家向け)
Server API は RID(Resource ID)を介して通信します。RID はサーバー側オブジェクトへの不透明なハンドルです。重要なルール:
# Create server-side canvas item (NO node overhead)
var ci_rid := RenderingServer.canvas_item_create()
RenderingServer.canvas_item_set_parent(ci_rid, get_canvas_item())
# CRITICAL: Keep resource references alive. RIDs don't count as references.
# If the Texture resource is GC'd, the RID becomes invalid silently.
var texture: Texture2D = preload("res://sprite.png")
RenderingServer.canvas_item_add_texture_rect(ci_rid, Rect2(-texture.get_size() / 2, texture.get_size()), texture)
Server を使ったスレッド処理
- シーンツリーはスレッドセーフではありません。一方、Server API(RenderingServer、PhysicsServer)は、Project Settings で有効にすればスレッドセーフです。
- シーンチャンク(インスタンス化 + add_child)をワーカースレッド上で構築できますが、ライブツリーに追加するには必ず
add_child.call_deferred()を使う必要があります。 - GDScript の Dictionary/Array:スレッド間の読み取りと書き込みは安全ですが、サイズ変更(append、erase、resize)には
Mutexが必要です。 - 同じ
Resourceを複数のスレッドから同時に読み込むことは絶対に避けてください。読み込みスレッドは 1 つだけ使用します。
🧩 パート 7:エキスパート向けコードパターン
一般的なアーキテクチャシステムやゲームプレイシステムのエキスパート向け実装です。
- コンポーネントレジストリ:一元化された辞書によるコンポーネントの取得です。
- 安全なシグナルハンドラー:解放済みオブジェクトへの参照によるクラッシュを防止します。
- 非同期リソースローダー:アセットのスレッド読み込みです。
- ステートマシン遷移ガード:状態変更を検証します。
- スレッドセーフなチャンクローダー:低レベルのサーバー API 構築です。
- 視野円錐検出:内積とレイキャストを使った、エキスパート向け NPC 視界です。
- サウンド伝播システム:音響遮蔽ロジックです。
- ステルス隠蔽ロジック:グローバルな可視性と隠蔽を管理します。
🔥 パート 8:Godot 4.x の落とし穴(熟練者向け)
@exportリソースはデフォルトで共有されます:複数のシーンインスタンスがすべて同じResourceを共有します。_ready()でresource.duplicate()を使うか、「Local to Scene」チェックボックスを有効にしてください。これは、初心者から最も多く報告されている Godot 4 のバグです。- シグナル構文はエラーなしで失敗します:
connect("signal_name", target, "method")(Godot 3 の構文)はコンパイルされますが、Godot 4 では何も起こりません。signal_name.connect(callable)を使う必要があります。 Tweenはノードではなくなりました:create_tween()で作成され、作成元ノードのライフサイクルに紐づきます。そのノードが解放されると、Tween も消滅します。永続的な Tween にはget_tree().create_tween()を使ってください。PhysicsBodyのレイヤーとマスク:collision_layerは「自分が何者か」、collision_maskは「何を検出するか」です。両方を同じ値に設定すると、自分自身との衝突が発生したり、検出を見逃したりします。- ホットパスでの
StringNameとStringの違い:StringName(&"key")はポインター比較(O(1))を使います。Stringは文字比較(O(n))を使います。_process内の辞書キーには、常にStringNameを使ってください。 @onreadyのタイミング:_init()の後、_ready()の実行中に処理されます。コンストラクター時のセットアップが必要な場合は_init()を使ってください。ツリーへのアクセスが必要な場合は、@onreadyまたは_ready()を使ってください。これらを混在させると、null が発生します。- サーバークエリによる停止:
_process内でRenderingServerやPhysicsServerのゲッター関数を呼び出すと、パイプラインの同期フラッシュが発生します。これらのサーバーは非同期で動作するため、データを要求すると、サーバーが追いつくまでパイプライン全体が停止します。 move_and_slide()の API 変更:衝突が発生したかどうかを示すboolを返します。速度は引数ではなく、プロパティになりました。move_and_slide()を呼び出す前にvelocity = dir * speedを設定してください。
📂 パート 9:モジュールディレクトリ(100 の設計図)
重要
現在のワークフローに必要なモジュールのみを読み込んでください。パート 2 の判断マトリックスを使って、どの連鎖をたどるか判断してください。
アーキテクチャと基盤
基礎 | コンポジション | アプリのコンポジション | シグナル | 自動読み込み | 状態 | リソース | テンプレート | アナリスト | 監査担当 | ビルダー | GDAS-reader | REA
バージョンアップグレード(外部ハブ): godot-version-migration — 全履歴を網羅するルーター(レガシー時代、3→4 の移行、4.0→4.7 の段階的移行)。ここにはミラーされていません。
GDScript & Testing
GDScript Mastery | Testing Patterns | Debugging/Profiling | Performance Optimization
2D Systems
2D Animation | 2D Physics | Tilemaps | Animation Player | Animation Tree | CharacterBody2D | Particles | Tweening | Shader Basics | Camera Systems
3D Systems
3D Lighting | 3D Materials | 3D World Building | Physics 3D | Navigation/Pathfinding | Procedural Generation | Raycasting
Gameplay Mechanics
Abilities | Combat | Dialogue | Economy | Inventory | Questing | RPG Stats | Turn System | Audio | Scene Transitions | Save/Load | Secrets | Collections | Waves | Harvesting | Time Trials | Revival | Monte Carlo Balancer
UI & UX
UI Containers | Rich Text | Theming | Input Handling | Seasonal Theming | Agent Vision
Connectivity & Platforms
Multiplayer | Server Logic | Export Builds | Desktop | Mobile | Web | Console | VR
Adaptation Guides
- Adapting Desktop -> Mobile
- Adapting Mobile -> Desktop
- Adapting Single -> Multiplayer
- Adapting 2D -> 3D
- Adapting 3D -> 2D
ジャンル別ブループリント(網羅)
アクション RPG | シューター | FPS シューター | RTS | MOBA | ローグライク | サバイバル | オープンワールド | メトロイドヴァニア | プラットフォーマー | 格闘 | ステルス | サンドボックス | ホラー | パズル | レース | リズム | スポーツ | バトルロイヤル | カードゲーム | ビジュアルノベル | 恋愛 | シミュレーション | タワーディフェンス | 放置クリッカー | パーティー | 教育
🐛 パート 10:エキスパート向け診断パターン
「見えないノード」バグ
症状:ノードはツリー内に存在するのに、描画されません。
エキスパートの診断手順:visible プロパティ → z_index → 親の CanvasLayer が誤ったレイヤーにある → modulate.a == 0 → カメラの near クリップ面の背後にある(3D) → SubViewport.render_target_update_mode が設定されていない → CanvasItem がどの CanvasLayer にも属していない(すべての背後に描画される)。
「入力が消費される」バグ
症状:クリックやキー入力が断続的に無視されます。
エキスパートの診断:別の Control ノードが mouse_filter = STOP の状態で対象に重なっています。または、モーダルの PopupMenu が未処理の入力を消費しています。または、別のスクリプトの _unhandled_input() が get_viewport().set_input_as_handled() を呼び出しています。
「物理演算の揺れ」バグ
症状:キャラクターが表面との接触時に振動します。
エキスパートの診断:Safe Margin が大きすぎます。または、移動に _physics_process ではなく _process を使用しているため、補間が一致していません。または、スポーン時にコリジョンシェイプが重なっており、互いを押し離したままになります。
「メモリリーク」
症状:プレイ中に RAM が徐々に増加します。
エキスパートの診断:queue_free() を呼び出しているものの、Array/Dictionary 内に参照が保持されています。または、CONNECT_REFERENCE_COUNTED でシグナルを接続した後、クリーンアップしていません。Profiler の「Objects」タブを使って、孤立したインスタンスを特定してください。親を持たない Node インスタンスを検索してください。
「フレームスパイク」
症状:FPS は安定しているのに、定期的に低下します。
エキスパートの診断:GDScript の GC 処理。または、大きなリソースを同期的に load() しています。または、NavigationServer の再ベイク。または、Server API のクエリによる停止(_process 内で RenderingServer からデータを要求)。組み込みの Profiler でプロファイリングし、関数単位のスパイクを確認してください。
🚀 パート 11:クイックスタート — Unity(C#)から Godot(GDScript)へ
Unity エコシステムから移行するシニアエンジニア向けのメンタルモデルの変化です。
1. ノードと GameObject/コンポーネント
Unity では、GameObject は Components のコンテナです。Godot では、すべてが Node です。
- Unity:
GameObject+Transform+MeshFilter+Script。 - Godot:スクリプトをアタッチした
MeshInstance3Dノード(TransformとMeshを兼ねます)。 - エキスパート向けの転換点:ノードの合成を活用してください。「Health Component」が必要な場合は、「Health」という名前の
NodeまたはArea3Dを子として追加します。ロジックのみのコンポーネントにはRefCountedを使い、メモリを節約してください。
2. シーンはネストされたプレハブ
Godot に「Prefabs」がないのは、すべてのシーンがプレハブだからです。
- シーンは別のシーン内に、何層にもわたってインスタンス化できます。
- エキスパート向けの転換点:再利用可能なシステム(Player、Enemy、UI Button)は、それぞれ独自の
.tscnファイルにしてください。これにより、「後順走査」(親より先に子の準備が完了する)が促進されます。
3. シグナルとイベント/アクションの違い
Godot の Signal システムは、オブザーバーパターンをネイティブに実装したものです。
- Unity:
event Action OnDeath;。 - Godot:
signal died。 - エキスパート向けの転換点:シグナルは第一級の要素です。インスペクターに表示され、動的に接続したり、エディターから接続したりできます。Unity のシングルトンマネージャーを再現するには、グローバルイベントに「シグナルバス」パターン(Autoload)を使用します。
4. ノードを拡張するスクリプト
ノードにスクリプトをアタッチすると、そのスクリプトがノードそのものになります。
- Unity:
GetComponent<MyScript>()。 - Godot:スクリプトはノードのクラスを拡張します(例:
extends CharacterBody3D)。 - エキスパート向けの転換点:コンパイル速度の向上とエディターの補完機能を利用するには、型付き GDScript(
var x: int = 5)を使用します。型がコンパイル時に判明している場合、型付き GDScript は最適化されたオペコードを使用します。
5. メモリ管理:ガベージコレクションによる停止なし
「GC スパイク」が発生することのある Unity の C# とは異なり、GDScript は参照カウントを使用します。
- エキスパート向けの転換点:オブジェクトは参照されなくなった時点ですぐに解放されます。これにより、決定論的なパフォーマンスが得られ、大規模な Unity プロジェクトでよく見られる断続的な「カクつき」を回避できます。
6. StringNames とパフォーマンス
Unity ではパフォーマンスのために int または Enum を使用します。Godot では StringName を使用します。
- エキスパート向けの転換点:辞書やシグナルの検索で、定数時間(O(1))のポインター比較を行うには
&"name"を使用します。