183 lines
4.8 KiB
Markdown
183 lines
4.8 KiB
Markdown
---
|
|
name: godot-gdscript-patterns
|
|
description: "GDScript best practices for Godot 4.x: node composition, typed signals, scene instantiation, resource management, singletons, event buses, and common design patterns. Use when writing or reviewing GDScript code in Godot."
|
|
license: MIT
|
|
compatibility:
|
|
- godot-4.0
|
|
- godot-4.1
|
|
- godot-4.2
|
|
- godot-4.3
|
|
- godot-4.4
|
|
- godot-4.5
|
|
- godot-4.6
|
|
- godot-4.7
|
|
metadata:
|
|
author: vl4dt
|
|
version: 0.1.0
|
|
tags:
|
|
- godot
|
|
- gdscript
|
|
- design-patterns
|
|
- signals
|
|
created: 2026-06-20
|
|
---
|
|
|
|
# GDScript Patterns for Godot 4.x
|
|
|
|
Best practices and patterns for writing clean, maintainable GDScript code.
|
|
|
|
## Node Hierarchy Best Practices
|
|
|
|
### Composition Over Inheritance
|
|
|
|
```gdscript
|
|
# Good: Small, focused scenes composed together
|
|
# Player.tscn contains:
|
|
# - CharacterBody2D (root)
|
|
# - Sprite2D (visual)
|
|
# - CollisionShape2D (physics)
|
|
# - AnimatedSprite2D (animation)
|
|
# - HealthComponent (Node — logic)
|
|
# - InventoryComponent (Node — logic)
|
|
|
|
# Avoid: Deep inheritance chains
|
|
# Player extends CharacterBody2D extends Node2D...
|
|
```
|
|
|
|
### Scene Instantiation Patterns
|
|
|
|
```gdscript
|
|
# preload() — Compile-time, for always-needed resources
|
|
@onready var bullet_scene = preload("res://scenes/entities/bullet.tscn")
|
|
|
|
# load() — Runtime, for conditional loading
|
|
var dialog_scene = load("res://scenes/ui/dialog.tscn")
|
|
|
|
# instantiate() — Create instance from scene
|
|
func spawn_bullet():
|
|
var bullet = bullet_scene.instantiate()
|
|
add_child(bullet)
|
|
```
|
|
|
|
## Typed Signals (Godot 4.x)
|
|
|
|
### Declaring Typed Signals
|
|
|
|
```gdscript
|
|
# Godot 4.x typed signal syntax
|
|
signal health_changed(new_health: int, max_health: int)
|
|
signal player_died(position: Vector2)
|
|
signal item_collected(item_data: Resource)
|
|
```
|
|
|
|
### Connecting Signals
|
|
|
|
```gdscript
|
|
# Auto-connect in editor (rename method to on_NodeName_signal)
|
|
func _on_health_changed(new_health: int, _max_health: int):
|
|
update_health_bar(new_health)
|
|
|
|
# Manual connection
|
|
func _ready():
|
|
enemy.health_depleted.connect(_on_enemy_defeated)
|
|
|
|
# Callable syntax (Godot 4.x)
|
|
button.pressed.connect(func: do_something())
|
|
```
|
|
|
|
## Scene Loading Patterns
|
|
|
|
### Resource Loading
|
|
|
|
```gdscript
|
|
# Preload for compile-time constants
|
|
const PlayerScene = preload("res://scenes/entities/player.tscn")
|
|
|
|
# Load for runtime/conditional loading
|
|
func load_level(level_name: String):
|
|
var path = "res://levels/%s.tscn" % level_name
|
|
var scene = load(path)
|
|
if scene:
|
|
current_level = scene.instantiate()
|
|
add_child(current_level)
|
|
```
|
|
|
|
### Resource Management
|
|
|
|
```gdscript
|
|
# Use Resource for game data
|
|
@export_file("*.tres") var player_data: String
|
|
var data: PlayerData = load(player_data) as PlayerData
|
|
|
|
# Scene packs for level data
|
|
var level_pack = preload("res://resources/data/level_pack.tscn")
|
|
```
|
|
|
|
## Common Patterns
|
|
|
|
### Singleton (Autoload) Pattern
|
|
|
|
```gdscript
|
|
# Add to Project Settings > Autoload as "GameData"
|
|
class_name GameData extends Node
|
|
|
|
var player_score: int = 0
|
|
var high_score: int = 0
|
|
|
|
func add_score(points: int):
|
|
player_score += points
|
|
if player_score > high_score:
|
|
high_score = player_score
|
|
```
|
|
|
|
### Event Bus Pattern
|
|
|
|
```gdscript
|
|
# Add to Project Settings > Autoload as "EventBus"
|
|
class_name EventBus extends Node
|
|
|
|
signal game_started()
|
|
signal level_completed(level_id: int)
|
|
signal player_died()
|
|
signal game_paused(paused: bool)
|
|
|
|
# Usage in any script
|
|
func _ready():
|
|
EventBus.level_completed.connect(on_level_completed)
|
|
```
|
|
|
|
### Node Path Best Practices
|
|
|
|
```gdscript
|
|
# Good: Use @onready for scene tree paths
|
|
@onready var health_bar = $UI/HealthBar as ProgressBar
|
|
@onready var sprite = $Sprite2D as Sprite2D
|
|
|
|
# Avoid: Hardcoded paths
|
|
var health_bar = get_node("UI/HealthBar") # Fragile to hierarchy changes
|
|
```
|
|
|
|
## Godot 4.7 GDScript Notes
|
|
|
|
- **DrawableTexture2D** — Create dynamic textures at runtime for procedural rendering
|
|
- **tween_await()** — Use await with tweens for sequential animations
|
|
- **Typed signals** are now the standard — prefer typed over untyped
|
|
|
|
## MCP Bridge Tools (Optional — Live Editor Integration)
|
|
|
|
When the MCP bridge is running (Phase 2), these tools can inspect and modify your project live:
|
|
|
|
- **`script_read`** — Read any script file from the project
|
|
- **`script_edit`** — Write updated script contents directly to disk
|
|
- **`script_validate`** — Validate GDScript syntax with `suggestTweenAwait: true` for Godot 4.7 migration
|
|
- **`scene_tree`** — Inspect the current scene hierarchy
|
|
- **`class_db_info`** — Query available methods/properties on any Godot class
|
|
|
|
> **Note:** MCP tools require the Godot editor to be running with the MCP plugin enabled. Skills work independently without the bridge.
|
|
|
|
## References
|
|
|
|
- [GDScript Style Guide](references/gdscript-style.md)
|
|
- [Signal Patterns Deep Dive](references/signals.md)
|
|
- [Resource Management](references/resource-management.md)
|