Claude
Skills
Sign in
Back

godot-game-loop-harvest

Included with Lifetime
$97 forever

Data-driven resource harvesting system (mining, logging, foraging) for Godot 4. Use when implementing gathering mechanics with tool/tier validation, health depletion, item spawning, and persistence.

Generalscripts

What this skill does


# Godot Game Loop: Harvest

Implement decoupled, data-driven gathering mechanics. This system handles tool validation, depletion, and respawning.

## 1. Component Reference

| Component | Asset | Description |
| :--- | :--- | :--- |
| **Resource Data** | [resource_data.gd](scripts/resource_data.gd) | `Resource`: Defines health, yield, and tool requirements. |
| **Tool Data** | [harvest_tool_data.gd](scripts/harvest_tool_data.gd) | `Resource`: Defines damage, type, and tier. |
| **Harvestable Node** | [harvestable_node.gd](scripts/harvestable_node.gd) | `StaticBody3D`: The world interaction entity. |
| **Respawn Manager** | [harvest_respawn_manager.gd](scripts/harvest_respawn_manager.gd) | `Node`: (Singleton) Manages world persistence. |
| **Inventory Manager**| [harvest_inventory_manager.gd](scripts/harvest_inventory_manager.gd) | `Node`: Hub for resource collection. |
| **Auto-Save Manager**| [harvest_autosave_manager.gd](scripts/harvest_autosave_manager.gd) | `Node`: Interval-based progress safety. |

## 2. Implementation Guide

### Step 1: Resource Setup
- Create a `HarvestResourceData` resource in the inspector.
- Configure `Required Tool Type` (e.g., "pickaxe", "axe") and `Required Tier`.
- Set `Yield Range` (Vector2i) and optional `Item Scene` for physical drops.

### Step 2: Node Configuration
- Attach `harvestable_node.gd` to a `StaticBody3D` node.
- Assign the `ResourceData` from Step 1.
- Assign a child `Node3D` (e.g., a Mesh) to `mesh_to_shake` for visual feedback.
- **Physics**: Ensure the node is on **Layer 1** for interaction.

### Step 3: Global Systems (Recommended)
- Add `harvest_respawn_manager.gd` as an **Autoload** named `HarvestRespawnManager`.
- The `HarvestableNode` will automatically use this manager if it is found at `/root/HarvestRespawnManager`.

## 3. Interaction & Signals

### Calling Hits
When a player interacts (e.g., via RayCast), call `apply_hit(tool_data)`.

```gdscript
if collider is HarvestableNode:
    collider.apply_hit(player_tool)
```

### Signal Map
| Signal | Payload | Integration |
| :--- | :--- | :--- |
| `harvested` | `(data, amount)` | Connect to `InventoryManager.add_resource`. |
| `took_damage` | `(curr, max)` | Connect to a Progress Bar or Damage Popups. |
| `interaction_failed`| `(reason: String)` | Handles `"wrong_tool"` or `"low_tier"` UI feedback. |

## NEVER Do

- **NEVER use float variables to store massively accumulated harvest resources** — Large floats lose precision, which can lead to "missing" resources in idle/clicker games. Always use `int` for core counts.
- **NEVER process gathering logic in _process() without multiplying rates by delta** — If you don't use `delta`, the harvesting speed will fluctuate wildly based on the player's hardware performance/framerate.
- **NEVER run heavy array mathematics for thousands of resources on the main thread** — This will cause micro-stutters. Distribute heavy calculations using `WorkerThreadPool`.
- **NEVER leave a gathering game running at full GPU utilization** — For UI-heavy harvest games, enable `OS.low_processor_usage_mode` to drastically reduce battery drain on mobile/laptops.
- **NEVER trust OS.get_ticks_msec() for offline progress** — This only tracks system uptime. Rely on `Time.get_unix_time_from_system()` to calculate real-world time passed between sessions.
- **NEVER use Timer nodes for precise audio-visual harvesting synchronization** — Timer nodes are subject to framerate variations. For frame-perfect sync, use code-based timers or the animation system.
- **NEVER couple your resource logic directly to UI counters** — Use a signal bus or event system to notify the UI of changes, keeping the game logic decoupled from the presentation.
- **NEVER constantly instantiate and destroy Label nodes for "floating numbers"** — Frequent allocation/deallocation leads to memory fragmentation. Use an object pool for damage/harvest popups.
- **NEVER modify a globally shared Resource without calling duplicate()** — If you modify a shared `Resource` (like a base crop yield), every instance using that resource will be updated. Use `duplicate(true)`.
- **NEVER access shared harvest data from background threads without a Mutex** — Simultaneous access will eventually corrupt your inventory data. Always use a `Mutex` to lock sensitive blocks.
- **NEVER hardcode yield values in your gathering scripts** — Use exports and custom `Resource` files so designers can balance the economy without touching the code.
- **NEVER use queue_free() on a harvested node before the VFX/SFX finish** — You'll cut off the "juice." Hide the mesh and disable collision, then `queue_free()` once the effect signals completion.
- **NEVER check tool requirements via string comparisons if possible** — Use enums or class types. Strings are prone to typos and are slower for high-frequency checks.
- **NEVER neglect to save the UNIX timestamp on exit** — If you forget this, you lose the ability to calculate offline earnings when the player returns.
- **NEVER scale collision shapes non-uniformly for harvestable objects** — This breaks the underlying physics calculations. Adjust the shape resource dimensions instead.

---

## Available Scripts

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

### [harvest_loop_patterns.gd](scripts/harvest_loop_patterns.gd)
Expert patterns for idle optimization, UNIX-based offline gains, and threaded resource processing.

### [resource_data.gd](scripts/resource_data.gd)
`Resource` container: Defines health, yield, and tool requirements for a harvestable object.

### [harvestable_node.gd](scripts/harvestable_node.gd)
`StaticBody3D`: The world interaction entity that handles hits, shakes, and depletion.

### [harvest_autosave_manager.gd](scripts/harvest_autosave_manager.gd)
Manages interval-based auto-saving for harvest progress using `FileAccess`.

---

## Expert Harvest Patterns

### 1. Proc-Gen Resource Veins (Noise)
Instead of random placement, use `FastNoiseLite` to create organic "clusters" of resources.

```gdscript
var noise = FastNoiseLite.new()
func _should_spawn(pos: Vector2) -> bool:
    # noise_val is -1.0 to 1.0. Higher thresholds create tighter veins.
    return noise.get_noise_2dv(pos) > 0.5 
```

### 2. Tool Durability System
Avoid hardcoding durability into the player; use a `Resource` to encapsulate tool state.

- **Benefit**: Allows easy serialization, swapping tools, and sharing logic across different tools.
- **Implementation**: See `harvest_tool_data.gd`. Tools should emit `durability_changed` and `tool_broken` signals.

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

Related in General