godot-genre-metroidvania
Installation
SKILL.md
Genre: Metroidvania
Expert blueprint for Metroidvanias balancing exploration, progression, and backtracking rewards.
NEVER Do (Expert Anti-Patterns)
World Design & Exploration
- NEVER allow "Soft-Locks" where a player is trapped; if they enter via a one-way path ("valve"), they MUST be able to leave using current abilities. Always design fail-safe escape routes.
- NEVER create empty dead ends; if a player backtracks to a remote area, they MUST be rewarded with a collectible, lore, or currency. Empty rooms are design failures.
- NEVER make backtracking purely repetitive; as the player gains movement (Dash/Teleport), traversal through old areas MUST become faster. Open shortcuts to bypass long, early routes.
- NEVER hide the critical path without "crumbs"; use distinct Landmarks, unique lighting, or environmental storytelling to build the player's mental map.
- NEVER design abilities that serve only one purpose; strictly implement dual-use traversal and combat functionality (e.g., a "Dash" that crosses gaps and dodges attacks).
Persistence & Mapping
- NEVER forget to save persistent room state; if a player opens a chest or defeats a boss, that state MUST remain saved when they leave and return.
- NEVER load interconnected rooms synchronously via
load(); strictly useResourceLoader.load_threaded_request()for seamless transitions. - NEVER track global progression within localized room scripts; strictly use Autoload Singletons for global ability flags and world state.
- NEVER use floating-point types for grid coordinates (minimaps/fog); strictly use
Vector2ito prevent precision jitter. - NEVER manipulate the SceneTree directly from a background loading thread; strictly use
call_deferred().
Physics & Controls
- NEVER calculate jump arcs or dashes inside
_process(); strictly use_physics_process()to prevent stutter. - NEVER multiply
CharacterBody2Dvelocity bydeltabeforemove_and_slide(); the engine handles this internally. - NEVER poll
is_action_just_pressed()inside_physics_process()for buffering; strictly capture events in_unhandled_input(). - NEVER use standard strings for high-frequency ability checks; strictly use
StringName(&"dashing") for pointer-speed comparisons. - NEVER iterate through every node to broadcast updates; strictly use
SceneTree.call_group()for efficient mass communication. - NEVER delete active room/player nodes via
free(); strictly usequeue_free()to avoid segmentation faults.
🛠Expert Components (scripts/)
Original Expert Patterns
- minimap_fog.gd - Grid-based fog of war that tracks visited rooms and persists via global save data.
- progression_gate_manager.gd - Central manager for ability-gated progression (Locks/Keys) and world persistence.
Modular Components
- platformer_jump_buffer.gd - Modular coyote time and jump buffering for high-fidelity movement.
- background_room_streamer.gd - Thread-safe background room preloading using
ResourceLoader. - safe_scene_switcher.gd - Deferred scene transition pattern for stable cross-room world-state switching.
- minimap_fog_revealer.gd - Vector2i-based fog-of-war clearing logic synced to player position.
- persistent_progression_system.gd - Autoload pattern for tracking global ability/collectible flags.
- ability_state_machine.gd - Optimized
StringNamepattern matching for traversal/combat states. - fast_wall_detector.gd - Direct
PhysicsServerqueries for performance-optimized wall detection. - save_station_broadcast.gd - Group-based entity resetting and healing logic on save interaction.
- decoupled_hazard_logic.gd - Interface-style pattern for generic damage interaction.
- smooth_room_camera_transition.gd - Tween-based camera limit interpolation for seamless room movement.
Core Loop
- Exploration: Player explores available rooms until blocked by a "lock" (obstacle).
- Discovery: Player finds a "key" (ability/item) or boss.
- Acquisition: Player gains new traversal or combat ability.
- Backtracking: Player returns to previous locks with new ability.
- Progression: New areas open up, cycle repeats.
Skill Chain
| Phase | Skills | Purpose |
|---|---|---|
| 1. Character | godot-characterbody-2d, state-machines |
Tight, responsive movement (Coyote time, buffers) |
| 2. World | godot-tilemap-mastery, level-design |
Interconnected map, biomes, landmarks |
| 3. Systems | godot-save-load-systems, godot-scene-management |
Persistent world state, room transitions |
| 4. UI | ui-system, godot-inventory-system |
Map system, inventory, HUD |
| 5. Polish | juiciness |
Effects, atmosphere, environmental storytelling |
Architecture Overview
1. Game State & Persistence
Metroidvanias require tracking the state of every collectible and boss across the entire world.
# game_state.gd (AutoLoad)
extends Node
var collected_items: Dictionary = {} # "room_id_item_id": true
var unlocked_abilities: Array[String] = []
var map_visited_rooms: Array[String] = []
func register_collectible(id: String) -> void:
collected_items[id] = true
save_game()
func has_ability(ability_name: String) -> bool:
return ability_name in unlocked_abilities
2. Room Transitions
Seamless transitions are key. Use a SceneManager to handle instancing new rooms and positioning the player.
# door.gd
extends Area2D
@export_file("*.tscn") var target_scene_path: String
@export var target_door_id: String
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"):
SceneManager.change_room(target_scene_path, target_door_id)
3. Ability System (State Machine Integration)
Abilities should be integrated into the player's State Machine.
# player_state_machine.gd
func _physics_process(delta):
if Input.is_action_just_pressed("jump") and is_on_floor():
transition_to("Jump")
elif Input.is_action_just_pressed("jump") and not is_on_floor() and GameState.has_ability("double_jump"):
transition_to("DoubleJump")
elif Input.is_action_just_pressed("dash") and GameState.has_ability("dash"):
transition_to("Dash")
Key Mechanics Implementation
Map System
A grid-based or node-based map is essential for navigation.
- Grid Map: Auto-fill cells based on player position.
- Room State: Track "visited" status to reveal map chunks.
# map_system.gd
func update_map(player_pos: Vector2) -> void:
var grid_pos = local_to_map(player_pos)
if not grid_map_data.has(grid_pos):
grid_map_data[grid_pos] = VISITED
ui_map.reveal_cell(grid_pos)
Ability Gating (The "Lock")
Obstacles that check for specific abilities.
# breakable_wall.gd
extends StaticBody2D
@export var required_ability: String = "super_missile"
func take_damage(amount: int, ability_type: String) -> void:
if ability_type == required_ability:
destroy()
else:
play_deflect_sound()
Common Pitfalls
- Softlocks: Ensure the player cannot get stuck in an area without the ability to leave. Design "valves" (one-way drops) carefully.
- Backtracking Tedium: Make backtracking interesting by changing enemies, opening shortcuts, or making traversal faster with new abilities.
- Empty Rewards: Every dead end should have a reward (health upgrade, lore, currency).
- Lost Players: Use visual landmarks and environmental storytelling to guide players without explicit markers (e.g., "The Statue Room").
Godot-Specific Tips
- Camera2D: Use
limit_left,limit_top, etc., to confine the camera to the current room bounds. Update these limits on room transition. - Resource Preloading: Preload adjacent rooms for seamless open-world feel if not using hard transitions.
- RemoteTransform2D: Use this to have the camera follow the player but stay detached from the player's rotation/scale.
- TileMap Layers: Use separate layers for background (parallax), gameplay (collisions), and foreground (visual depth).
Design Principles (from Dreamnoid)
- Ability Versatility: Abilities should serve both traversal and combat (e.g., a dash that dodges attacks and crosses gaps).
- Practice Rooms: Introduce a mechanic in a safe environment before testing the player in a dangerous one.
- Landmarks: Distinct visual features help players build a mental map.
- Item Descriptions: Use them for "micro-stories" to build lore without interrupting gameplay.
Reference
- Master Skill: godot-master
Weekly Installs
73
Repository
thedivergentai/…c-skillsGitHub Stars
137
First Seen
2 days ago
Security Audits