6.3 KiB
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 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
Signal-Based Decoupling (Recommended)
# 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 patternsscript_read/script_edit— Read and modify architecture scriptsclass_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.