Claude
Skills
Sign in
Back

godot-game-loop-collection

Included with Lifetime
$97 forever

Use when implementing collection quests, scavenger hunts, or "find all X" objectives.

Generalscripts

What this skill does


# Collection Game Loops

## Overview
This skill provides a standardized framework for "Collection Loops" – gameplay objectives where the player must find and gather a specific set of items (e.g., hidden eggs, data logs, coins).

## NEVER Do

- **NEVER use free() to destroy an active state node or level** — This can cause crashes if the node is still processing. Always use `queue_free()` to safely dispose of it at the end of the frame.
- **NEVER calculate physics-dependent game state in _process()** — Movement and precise collisions must happen in `_physics_process()` to stay synced with the engine's fixed timestep.
- **NEVER execute heavy state transitions (like loading massive levels) synchronously** — Calling `load()` on a huge scene stalls the main thread. Use `ResourceLoader.load_threaded_request()`.
- **NEVER use exact floating-point equality (==) for time-based states** — Floating-point errors will eventually cause missed triggers. Use `is_equal_approx()` or relative comparisons.
- **NEVER manipulate the active SceneTree from a background thread** — The SceneTree is not thread-safe. Use `call_deferred()` to push results back to the main thread.
- **NEVER rely on a monolithic "GameManager" with hardcoded absolute paths** — This creates tight coupling. Use groups, signals, and exported references for a modular architecture.
- **NEVER assume child nodes are ready before their parent** — `_ready()` executes from bottom-to-top. If you need child references, use `@onready` or `await ready`.
- **NEVER use string-based signals for critical state transitions** — Avoid `connect("signal", _on_func)`. Use the Signal object syntax (`signal.connect(_on_func)`) for compile-time validation.
- **NEVER poll for input state every frame for discrete menu events** — Use the `_unhandled_input()` callback to cleanly intercept events without wasting CPU cycles in `_process()`.
- **NEVER crash the engine intentionally via CRASH_NOW_MSG** — Regular state handling should always recover gracefully. Crashing is for unrecoverable internal engine failures.
- **NEVER hardcode spawn positions in code** — Always use `Marker3D` or `CollisionShape3D` nodes in the scene so designers can adjust layout without touching code.
- **NEVER neglect "juice" before an item disappears** — Immediate `queue_free()` feels dry. Always spawn particles or play a sound before removal.
- **NEVER use global variables for local collection progress** — Keep counts encapsulated within the `CollectionManager` and emit signals to update the UI.
- **NEVER leave orphaned nodes in the tree during state swaps** — Always ensure the previous level/state is properly queued for deletion before instantiating the new one.
- **NEVER scale collision shapes non-uniformly for collectibles** — This breaks collision detection math. Adjust the internal shape resource properties instead.

---

## Available Scripts

> **MANDATORY**: Read the appropriate script before implementing the corresponding pattern.

### [collection_loop_patterns.gd](scripts/collection_loop_patterns.gd)
Collection of 10 expert patterns: Custom MainLoop extensions, deferred scene switching, threaded loading, and frame throttling.

### [collection_manager.gd](scripts/collection_manager.gd)
The central brain of the hunt. Tracks progress and manages completion signals.

### [collection_compass.gd](scripts/collection_compass.gd)
Spatial radar for pointing towards the nearest collectible using vector math.

---

## Expert Collection Patterns

### 1. Persistent Collection (Save/Load)
To ensure progress survives restarts, use `FileAccess` to store data in `user://`.

```gdscript
func save_progress(data: Dictionary):
    var file = FileAccess.open("user://save.dat", FileAccess.WRITE)
    file.store_var(data) # Binary serialization for performance

func load_progress() -> Dictionary:
    if not FileAccess.file_exists("user://save.dat"): return {}
    var file = FileAccess.open("user://save.dat", FileAccess.READ)
    return file.get_var()
```

### 2. Collection Archive UI (Silhouettes)
Display uncollected items as silhouettes without extra textures by using `modulate`.

- **Technique**: Use an `ItemList` or `TextureRect` grid.
- **Silhouette**: Set `modulate = Color(0, 0, 0, 0.5)` for locked items.
- **Reveal**: Set `modulate = Color(1, 1, 1, 1)` once collected.

## Reference
- Master Skill: [godot-master](../godot-master/SKILL.md)

Related in General