godot-composition について
深い継承階層ではなく、連携するNodeでゲームエンティティを構成するGodotスキルです。再利用可能な機能を組み立てる開発者向けに、型付き依存注入、シグナル通信、専用コンポーネントスクリプトを扱います。
主な機能
- 01単一責任のNodeコンポーネント
- 02オーケストレーターによるエンティティ配線
- 03型付き@export依存注入
- 04シグナルで通知しメソッドで呼び出す通信
- 05再利用可能な体力、移動、状態コンポーネント
活用シーン
- 01体力やダメージ処理をエンティティスクリプトから分離
- 02プレイヤーや敵の機能をコンポーネントで構成
- 03親スクリプトに依存せずコンポーネントを接続
- 04子Nodeでステートマシンを構成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ thedivergentai/ game-dev-agentic-skills --skill godot-compositionインストール後、Claude Code で/godot-compositionを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/migration-notes.mdorchestrator-recipes.mdresources/health_component.gdhitbox_component.gdscripts/composition_root_init.gdfollower_component.gdhealth_component.gdhit_box_component.gdhurt_box_component.gdinteraction_component.gdstate_component_vsm.gdstatus_effect_component.gdvelocity_component.gdvisual_sync_component.gd詳細
基本理念
このスキルは、継承よりもコンポジション(「持つ」対「である」)を徹底します。 Godotでは、ノードがコンポーネントです。複雑なエンティティ(プレイヤー)は、特化したワーカーノード(コンポーネント)を管理するオーケストレーターにすぎません。
基本ルール
- 単一責任:1つのスクリプトが担う役割は1つです。
- カプセル化:コンポーネントは「自分のことだけ」に専念します。内部ロジックを処理しますが、自分の所有者が 誰か は把握しません。
- オーケストレーター:ルートスクリプト(例:
player.gd)はロジックを一切含みません。状態の管理と、コンポーネント間のデータ受け渡しのみを行います。 - 疎結合:コンポーネントはシグナル(上方向)とメソッド(下方向)で通信します。
判断基準 — コンポジション、オートロード、継承
| 状況 | 選択肢 |
|---|---|
| ゲームプレイエンティティの振る舞い(HP、ヒットボックス、移動、インタラクション) | コンポジション — 子コンポーネント+オーケストレーター(composition_root_init.gd) |
| シーンをまたぐサービス(オーディオバス、セーブ、ネットワーク、経済台帳) | オートロード — プレイヤーのコンポーネントではありません |
| 真の「である」関係に基づくエンジンの特殊化(ライフサイクルを共有するカスタム Control/Node) | 継承の例外 — まれなケースです。「銃を追加する」「HPを追加する」用途には決して使いません |
利用可能なスクリプト
health_component.gd
あらゆるエンティティの寿命、ダメージロジック、死亡シグナルを管理する特化型ノードです。
hit_box_component.gd
Areaベースのコンポーネントです。ダメージを受け取り、HealthComponentに処理を委任します。
hurt_box_component.gd
HitBoxComponentにダメージを与えるためのAreaベースのコンポーネントです。
velocity_component.gd
プレイヤーや敵で再利用できる、カプセル化された移動および加速ロジックです。
interaction_component.gd
コンテキストに応じたアクションに注入されたCallableロジックを使用する、疎結合なインタラクションハンドラーです。
follower_component.gd
NodePathの注入を使用して、エンティティを滑らかに追従させる疎結合な追跡ロジックです。
state_component_vsm.gd
個々の状態として子ノードを使用する、コンポーネントベースのステートマシンパターンです。
status_effect_component.gd
エフェクトシーンを子として積み重ね、一時的な修飾効果(バフ/デバフ)を管理します。
visual_sync_component.gd
論理状態(速度/方向)と視覚表現(スプライトの反転)を分離します。
composition_root_init.gd
必ず最初に読んでください — 型付き@exportを使用したオーケストレーターの配線(インスペクター/シーン内の%UniqueNames)。コンポーネントには$/get_nodeを決して使わないというルールに準拠しています。
構成で絶対に行わないこと
- 深い継承チェーンは絶対に使用しないでください(例:
Player > Entity > LivingThing > Node)。リファクタリングが困難で脆弱な「神クラス」が生まれます [21]。 - コンポーネントに
get_node()や$を絶対に使用しないでください。シーンツリーの再配置で動作しなくなります。必ず@exportまたは%UniqueNamesを使用してください [22]。 - コンポーネントから親スクリプトを直接参照させないでください。コンポーネントを再利用できなくなります。シグナルまたは依存性注入を使用してください [23]。
- Input、Physics、Game Logic を1つのスクリプトに混在させないでください。これは単一責任の原則に反します。専用コンポーネントに分割してください [24, 13]。
- 特定のSceneTree構造を必要とするコンポーネントは絶対に作成しないでください。コンポーネントは「自己中心的」であり、自身のプロパティと直接の子ノードだけを考慮するべきです。
- 「機能を追加する」ために継承を絶対に使用しないでください。敵に射撃させたい場合は
ShootingComponentを追加し、ShooterEnemyを継承させないでください。 - コンポーネントの依存関係をハードコードしないでください。
CombatComponentがHealthComponentを必要とする場合は、_ready()で取得するか、親から注入してください [11]。 - Godotノードを純粋なデータとして扱わないでください。ノードはライフサイクル(
_process)とシグナルを提供します。データだけが必要な場合はResourceを使用してください。 - コンポーネントでNodeのライフサイクルを無視しないでください。親の状態にかかわらず必ず実行する必要があるセットアップやクリーンアップには、
_enter_tree()と_exit_tree()を使用してください。 - コンポーネントへのアクセス箇所を隠さないでください。親がインスペクターで接続できるように、
NodePathまたはCallableプロパティを公開してください [13]。
実装標準
1. 接続戦略:型付きエクスポート
ツリーの順序に依存しないでください。静的型付けを使用した @export による明示的な依存性注入を使用してください。
厳密なgodot-compositionを実現する「Godot流」の方法:
# The Orchestrator (e.g., player.gd)
class_name Player extends CharacterBody3D
# Dependency Injection: Define the "slots" in the backpack
@export var health_component: HealthComponent
@export var movement_component: MovementComponent
@export var input_component: InputComponent
# Use Scene Unique Names (%) for auto-assignment in Editor
# or drag-and-drop in the Inspector.
2. コンポーネントの考え方
コンポーネントを型として認識させるには、class_name を定義する必要があります。
標準的なコンポーネントのひな形:
class_name MyComponent extends Node
# Use Node for logic, Node3D/2D if it needs position
@export var stats: Resource # Components can hold their own data
signal happened_something(value)
func _ready() -> void:
_validate_dependencies()
func _validate_dependencies() -> void:
# 2. Dependency-Validation: Fail early during development if setup is wrong [2]
# NOTE: assert() is stripped in release builds [10].
assert(stats != null, "Stats Resource missing on %s" % name)
func do_logic(delta: float) -> void:
# Perform specific task
pass
標準コンポーネント — スクリプトを使用
Input/Movement/Health のインラインレシピは削除されました。必須:composition_root_init.gd から始めて、該当するスクリプトを読み込んでください。
- Health/death:health_component.gd
- Damage areas:hit_box_component.gd、hurt_box_component.gd
- Motion:velocity_component.gd
- Interact/follow/VFX sync:interaction_component.gd、follower_component.gd、visual_sync_component.gd
- States/statuses:state_component_vsm.gd、status_effect_component.gd
型付きの @export による接続方法は、上記の実装標準に記載されています。
エキスパート向け構成パターン
1. ステートコンポーネントパターン(FSM)
複雑な動作を、ステートとして機能する子ノードにカプセル化します。親のStateComponentは、アクティブな子にライフサイクル呼び出しを委譲します [4, 6]。
必須:state_component_vsm.gd を読み、インラインのStateMachineを貼り付けないでください。より高度なVSM/階層型FSMについては、godot-state-machine-advanced を開いてください。
2. コンポーネントレジストリ(O(1)検索)
兄弟ノード間の通信に、低速なツリー走査を使わないでください。ready時に子ノードをDictionaryに登録します(名前またはグループで登録)。
var _components: Dictionary = {}
func _ready() -> void:
for child in get_children():
_components[child.name] = child
for group in child.get_groups():
_components[group] = child
func get_comp(key: StringName) -> Node:
return _components.get(key)
3. 依存関係の検証
get_node_or_null のパスではなく、@export のアサートを使用して、早い段階で失敗させてください(ツリーの再配置でパスが壊れます)。
@export var health_component: HealthComponent
@export var input_component: InputComponent
func _ready() -> void:
assert(health_component != null, "Missing HealthComponent export!")
assert(input_component != null, "Missing InputComponent export!")
Input/Movement/Healthのオーケストレーターのレシピとレジストリの詳細については、必ずorchestrator-recipes.md を参照してください。composition_root_init.gd と1つのコンポーネントスクリプトで十分な場合は、読み込まないでください。
パフォーマンスに関する注意
ノードは軽量です。エンティティごとに10〜20個のノードを追加しても問題ありません。コンポジションによる整理上のメリットは、Node インスタンスのわずかなメモリーコストを大きく上回ります。
参考資料
段階的な情報開示:特定のAPIを調査するときにのみ公式ドキュメントのリンクを開き、同じ領域のスキルへ引き継ぐときに関連スキルを読み込みます。スキル群全体を事前に読み込まないでください。
公式ドキュメント
- シーンの整理 — シグナルを上へ、呼び出しを下へ伝える標準的な所有関係により、オーケストレーターがコンポーネント同士を密結合させずに接続できます。
- ノードとシーン — Godotがノードを再利用可能な構成要素(コンポーネント)として扱い、それらをエンティティのシーンに組み立てる理由を説明します。
- Godotのクラスとは — ゲームプレイエンティティには、深い継承ツリーよりもシーンコンポジションと
class_nameコンポーネントを優先します。 - あらゆるものにノードを使うのを避ける方法 — 純粋なデータはリソースに保持し、ライフサイクル、シグナル、処理タイミングにはノードを使います。
- ロジックの配置に関する方針 — シーンツリー内のゲームロジックの配置方法を示します。親がオーケストレーションを担い、子は単一の役割に専念します。
- データに関する方針 — コンポーネントが使用するステータスや設定に、ノード、リソース、プレーンデータのどれを選ぶかを説明します。
- シグナルの使用 — 親が逆方向の依存関係を持たずに接続できる、過去形のコンポーネントイベント(
health_depleted、state_changed)について説明します。 - GDScriptのエクスポートプロパティ — 壊れやすい
$パスの代わりに、インスペクターで依存関係を注入するための型付き@exportスロットを説明します。 - シーン固有ノード — コンポジションルートを接続する際、シーンツリーの並べ替え後も使える
%Nameによる参照を説明します。 - グループ — 継承を使わずに、インターフェース風の検索やO(1)形式のレジストリー検索を行えるよう、コンポーネントにタグを付けます。
- Godotの通知 — コンポーネントの依存関係を検証・接続する際に安全な
_ready/ ツリーへの進入タイミングを説明します。 - リソース — 最大体力や速度などの調整可能な値をリソースとして共有し、コンポーネントを複数のエンティティで再利用できるようにします。
関連スキル
前提条件
- godot-project-foundations — すべてのコンポジションルートが前提とする、シーンの所有関係、プロジェクト構成、インスペクターでの接続規約について説明します。
- godot-gdscript-mastery — 型付きコンポーネントAPIに必要な
class_name、型付き@export、Callable、assertのパターンについて説明します。 - godot-signal-architecture — シグナルを上へ、呼び出しを下へ伝える接続規約により、独立性を保つコンポーネントが親スクリプトを直接参照しないようにします。
補完
- godot-resource-data-patterns — ステータスと効果の定義には Resources を使用し、コンポジションノードが実行時の変更を管理して変更イベントを発行します。
- godot-state-machine-advanced — オーケストレーターを肥大化させず、StateComponent として組み込める子ノードの FSM / VSM パターンです。
- godot-input-handling — 感知レイヤーの InputComponents はアクションのサンプリングのみを行い、親ノードが方向を移動コンポーネントに渡します。
- godot-characterbody-2d — 物理ボディの移動 API である VelocityComponents を、コンポジションルートから
move_and_slideを介して呼び出します。 - godot-2d-physics — HitBox/HurtBox/Interaction コンポーネントが依存する Area2D のレイヤー、マスク、オーバーラップのルールです。
- godot-scene-management — エンティティをコンポジション済みのシーンとしてスポーン/デスポーンし、インスタンスの差し替え時にエクスポートを再配線します。
下流/利用者
- godot-combat-system — ダメージ処理パイプラインでは、戦闘オーケストレーターの下に Health/HitBox/HurtBox コンポーネントを組み立てます。
- godot-ability-system — あらゆるキャスターをサブクラス化するのではなく、能力をコンポジション済みのワーカー(クールダウン、ターゲティング)としてアタッチします。
- godot-rpg-stats — ステータスシートは、変更シグナルとともに Resources として Health/StatusEffect コンポーネントに値を渡します。
- godot-monte-carlo-balancer — エンティティの構成を確定する前に、調整可能なコンポーネントのエクスポート値(HP、ダメージ、速度)をシミュレーションします。
- godot-composition-apps — 同じ Has-A ノードコンポジションを、ゲームプレイのエンティティではなくツール/アプリに適用します。
マスター
- godot-master — ライブラリのルーターおよびミラー化されたモジュールエントリです。複数の領域にまたがるアーキテクチャ上の課題を担当するドメインスキルを探す際に参照してください。