Skills/godot-architecture/SKILL.md

6.3 KiB

name description license compatibility metadata
godot-architecture Game architecture patterns for Godot 4.x: ECS-like composition, scene organization, dependency injection via signals, service locator vs direct reference, and scalable project structure. Use when designing or refactoring a Godot game's overall architecture. MIT
godot-4.0
godot-4.1
godot-4.2
godot-4.3
godot-4.4
godot-4.5
godot-4.6
godot-4.7
author version tags created
vl4dt 0.1.0
godot
architecture
ecs
composition
service-locator
2026-06-21

Godot Game Architecture Patterns

Architectural approaches for building scalable, maintainable Godot games.

Scene Composition Over Inheritance

Godot's scene system naturally supports composition. Build complex behavior by combining small, focused scenes rather than deep inheritance chains.

Component-Based Composition

# Player.tscn hierarchy:
# CharacterBody2D (root — movement logic)
#   Sprite2D (visual)
#   CollisionShape2D (physics body)
#   HealthComponent (Node — health logic, emits signals)
#   InventoryComponent (Node — item management)
#   ExperienceComponent (Node — XP/leveling)

# Each component is a standalone .tscn with its own script.
# The player scene composes them without inheritance coupling.

Component Script Pattern

class_name HealthComponent extends Node

signal health_changed(current: int, maximum: int)
signal died()

@export var max_health: int = 100
var current_health: int = 100:
    set(value):
        current_health = clampi(value, 0, max_health)
        health_changed.emit(current_health, max_health)
        if current_health <= 0:
            died.emit()

func take_damage(amount: int) -> void:
    current_health -= amount

func heal(amount: int) -> void:
    current_health += amount

Dependency Management Patterns

Direct Reference (Simple Cases)

# Good for tightly-coupled parent-child relationships
@onready var health_component = $HealthComponent as HealthComponent
@onready var animation_player = $AnimationPlayer as AnimationPlayer
# Components communicate via signals — no direct references needed
func _ready():
    $HealthComponent.died.connect(_on_player_died)
    $InventoryComponent.item_collected.connect(_on_item_collected)

func _on_player_died():
    get_tree().reload_current_scene()

Service Locator (Autoload Singletons)

# GameManager.gd — added as autoload in Project Settings
extends Node

var current_level: int = 0
var player_score: int = 0
var is_paused: bool = false

signal game_started()
signal game_paused(paused: bool)
signal level_completed(level_id: int, score: int)

# Access from anywhere: GameManager.current_level

When to Use Each Approach

Pattern Use When Avoid When
Direct reference ($Path) Parent-child, same scene Cross-scene communication
Signals Decoupled components, event-driven flow Simple data access
Autoload singleton Global state (score, settings) Per-instance data
Resource-based Data that needs saving/loading Runtime-only behavior

ECS-Like Patterns in Godot

Godot isn't a true ECS engine, but you can approximate entity-component systems:

Entity Registry Pattern

class_name EntityRegistry extends Node

# Tracks all active entities by type
var _entities: Dictionary = {}

func register(entity_id: String, entity: Node) -> void:
    if not _entities.has(entity_id):
        _entities[entity_id] = []
    _entities[entity_id].append(entity)

func unregister(entity_id: String, entity: Node) -> void:
    if _entities.has(entity_id):
        _entities[entity_id].erase(entity)

func get_all(entity_id: String) -> Array:
    return _entities.get(entity_id, [])

Data-Driven with Resources

# EntityData.tres — defines entity properties without code
class_name EntityData extends Resource

@export var entity_name: String = ""
@export var health: int = 100
@export var speed: float = 100.0
@export var components: Array[String] = []  # Component scene paths

Project Structure Patterns

Feature-Based Organization

res://
├── core/               # Engine-level systems (autoloads, event bus)
│   ├── GameManager.gd
│   └── EventBus.gd
├── features/           # Game features as self-contained modules
│   ├── combat/
│   │   ├── scripts/
│   │   ├── scenes/
│   │   └── resources/
│   ├── inventory/
│   │   ├── scripts/
│   │   ├── scenes/
│   │   └── resources/
│   └── dialogue/
├── levels/             # Level scenes and data
├── ui/                 # UI components and screens
└── assets/             # Art, audio, fonts

Module Pattern for Large Projects

# FeatureModule.gd — reusable feature registration pattern
class_name FeatureModule extends Node

func initialize() -> void:
    pass  # Override in subclasses

func cleanup() -> void:
    pass  # Override in subclasses

# Usage: CombatModule.gd extends FeatureModule
# - Registers signals with EventBus
# - Spawns combat-related autoloads if needed
# - Connects to game lifecycle events

Godot 4.7 Architecture Notes

  • tween_await() — Use for sequential animations without callback chains in component scripts
  • DrawableTexture2D — Procedural rendering for debug visualization of entity bounds
  • Perfetto tracing — Profile architecture decisions with CPU/GPU trace markers

MCP Bridge Tools (Optional — Live Editor Integration)

When the MCP bridge is running (Phase 2), these tools can inspect and modify your project live:

  • scene_tree — Inspect scene hierarchy to audit composition patterns
  • script_read / script_edit — Read and modify architecture scripts
  • class_db_info — Query available methods on Godot classes for integration points

Note: MCP tools require the Godot editor to be running with the MCP plugin enabled. Skills work independently without the bridge.

References