
Godot Genre Survival
- 145 installs
- 454 repo stars
- Updated July 28, 2026
- thedivergentai/gd-agentic-skills
Use godot-genre-survival for development tasks
About
godot-genre-survival: A skill for development. This provides functionality for development workflows.
- godot-genre-survival
Godot Genre Survival by the numbers
- 145 all-time installs (skills.sh)
- +10 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #2,537 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-genre-survivalAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 145 |
|---|---|
| repo stars | ★ 454 |
| Last updated | July 28, 2026 |
| Repository | thedivergentai/gd-agentic-skills ↗ |
What it does
Use godot-genre-survival for development tasks
Files
Genre: Survival
Resource scarcity, needs management, and progression through crafting define survival games.
NEVER Do (Expert Anti-Patterns)
Physiology & Needs
- NEVER use constant "Needs" decay; strictly scale with activity (e.g., Sprinting drains hunger 3x faster than idling).
- NEVER use Instant Death for starvation/dehydration; strictly trigger gradual HP drain and provide distinct visual/audio warnings.
- NEVER use float timers for exact life-critical checks; strictly use
is_equal_approx()or<=to prevent 0.0 precision misses. - NEVER represent world time/day cycles within UI scripts; strictly use an AutoLoad (Singleton) to decouple state from visuals.
Gathering & Inventory
- NEVER make gathering tedious without progression; strictly implement Tiered Tool Scaling (e.g., Stone Axe = 1 wood/hit, Steel Axe = 5 wood/hit) to reward technical advancement.
- NEVER allow infinite inventory stacking; strictly use Weight Capacity or strict Stack Limits (e.g., 64 items) to force strategic resource management.
- NEVER force players to "Guess" crafting recipes; strictly use a Discovery System where recipes unlock upon acquiring materials.
- NEVER forget to duplicate(true) a shared Resource (like Item Durability); otherwise, all instances will break simultaneously.
- NEVER store heavy item/crafting definitions in Node properties; strictly use custom Resource containers for lightweight data.
World & Performance
- NEVER spawn threats at Respawn Points; strictly enforce a Safe Zone radius (Beds/Spawn) where enemy spawning is prohibited.
- NEVER instance 10,000 individual
MeshInstance3Dnodes for foliage; strictly use MultiMeshInstance3D for batched draw calls. - NEVER load massive world chunks synchronously; strictly use
ResourceLoader.load_threaded_request()to prevent hitches. - NEVER save complex dictionaries to standard text files; strictly use binary serialization for speed and size efficiency.
- NEVER run procedural terrain/noise algorithms on the main thread; strictly offload to the WorkerThreadPool.
- NEVER hardcode massive crafting tables in GDScript; strictly use
ConfigFileor JSON for easy balancing and modding.
---
🛠 Expert Components (scripts/)
Original Expert Patterns
- inventory_slot_resource.gd - Data-driven inventory slot model using Resources for seamless serialization and durability tracking.
- survival_patterns.gd - 10 Essential Survival Expert Patterns (Decay scaling, Environment tweens, MultiMesh optimization).
Modular Components
- interactable.gd - Universal interface for harvesting, picking up items, and world triggers.
- inventory_data.gd - Core business logic for grid-based inventories and stacking.
- inventory_slot_data.gd - Lightweight data container for UI-to-Logic inventory communication.
- inventory_data.gd - High-performance Resource-based storage with stack limits and metadata support.
- inventory_data.gd - Master item definition for weight, stack-size, and consumption effects (Resource-based).
---
| Phase | Skills | Purpose |
|---|---|---|
| 1. Data | resources, custom-resources | Item data (weight, stack size), Recipes |
| 2. UI | grid-containers, drag-and-drop | Inventory management, crafting menu |
| 3. World | tilemaps, noise-generation | Procedural terrain, resource spawning |
| 4. Logic | state-machines, signals | Player stats (Needs), Interaction system |
| 5. Save | file-system, json-serialization | Saving world state, inventory, player stats |
Architecture Overview
1. Item Data (Resource-based)
Everything in the inventory is an Item.
# item_data.gd
extends Resource
class_name ItemData
@export var id: String
@export var name: String
@export var icon: Texture2D
@export var max_stack: int = 64
@export var weight: float = 1.0
@export var consumables: Dictionary # { "hunger": 10, "health": 5 }2. Inventory System
A grid-based data structure.
# inventory.gd
extends Node
signal inventory_updated
var slots: Array[ItemSlot] = [] # Array of Resources or Dictionaries
@export var size: int = 20
func add_item(item: ItemData, amount: int) -> int:
# 1. Check for existing stacks
# 2. Add to empty slots
# 3. Return amount remaining (that couldn't fit)
pass3. Interaction System
A universal way to harvest, pickup, or open things.
# interactable.gd
extends Area2D
class_name Interactable
@export var prompt: String = "Interact"
func interact(player: Player) -> void:
_on_interact(player)
func _on_interact(player: Player) -> void:
pass # Override thisKey Mechanics Implementation
Needs System
Simple float values that deplete over time.
# needs_manager.gd
var hunger: float = 100.0
var thirst: float = 100.0
var decay_rate: float = 1.0
func _process(delta: float) -> void:
hunger -= decay_rate * delta
thirst -= decay_rate * 1.5 * delta
if hunger <= 0:
take_damage(delta)Crafting Logic
Check if player has ingredients -> Remove ingredients -> Add result.
func craft(recipe: Recipe) -> bool:
if not has_ingredients(recipe.ingredients):
return false
remove_ingredients(recipe.ingredients)
inventory.add_item(recipe.result_item, recipe.result_amount)
return true
### 4. Tiered Tool Scaling
Scaling resource yield with tool quality (`item_data.gd` metadata):
- **Stone Axe**: 1 yield per hit, 3s harvest time.
- **Steel Axe**: 5 yield per hit, 1.5s harvest time.
- **Auto-Saw**: Constant yield stream while within proximity.
### 5. Spawn Safe Zones
Preventing "Spawn Camping" via check:func get_spawn_point() -> Vector3: var point = find_random_point() for bed in get_tree().get_nodes_in_group("player_beds"): if point.distance_to(bed.global_position) < safe_radius: return get_spawn_point() # Re-roll return point
Godot-Specific Tips
- TileMaps: Use
TileMap(Godot 3) orTileMapLayer(Godot 4) for the world. - FastNoiseLite: Built-in noise generator for procedural terrain (trees, rocks, biomes).
- ResourceSaver: Save the
Inventoryresource directly to disk if it's set up correctly withexportvars. - Y-Sort: Essential for top-down 2D games so player sorts behind/in-front of trees correctly.
Common Pitfalls
1. Tedium: Harvesting takes too long. Fix: Scale resource gathering with tool tier (Stone Axe = 1 wood, Steel Axe = 5 wood). 2. Inventory Clutter: Too many unique items that don't stack. Fix: Be generous with stack sizes and storage options. 3. No Goals: Player survives but gets bored. Fix: Add a tech tree or a "boss" to work towards.
---
🚀 Elite Technical Implementations (Batch 09)
1. Grid-Map-Snap Pattern (Base-Building)
For performant base-building in 3D, use the GridMap node. It uses octant-based optimization to handle thousands of structure pieces with minimal CPU overhead compared to standard MeshInstance3D nodes.
class_name BaseBuilder extends Node3D
@export var grid_map: GridMap
@export var wooden_wall_item_id: int = 1
## Snaps a global 3D coordinate to the grid and places a structure.
func build_structure(hit_position: Vector3) -> void:
# 1. Convert global space to grid map coordinate.
var grid_pos: Vector3i = grid_map.local_to_map(hit_position)
# 2. Verify the target cell is empty.
if grid_map.get_cell_item(grid_pos) == GridMap.INVALID_CELL_ITEM:
# 3. Place the structure item at the snapped coordinates.
grid_map.set_cell_item(grid_pos, wooden_wall_item_id)
print("Structure successfully snapped and built!")
else:
push_warning("Cannot build here: Cell is already occupied.")2. AStar-Path-Avoidance (Dynamic AI Routing)
When players build structures, AI must immediately find new paths. AStarGrid2D provides an efficient way to update the pathfinding graph in real-time by flagging specific cells as solid.
class_name AIPathingSystem extends Node
var _astar_grid: AStarGrid2D
func _ready() -> void:
_astar_grid = AStarGrid2D.new()
_astar_grid.region = Rect2i(-100, -100, 200, 200)
_astar_grid.cell_size = Vector2(1, 1)
_astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES
_astar_grid.update()
## Called whenever a structure is placed in the world.
func on_structure_built(grid_coords: Vector2i) -> void:
if _astar_grid.is_in_bounds(grid_coords.x, grid_coords.y):
# Mark the point as solid, instantly routing AI around the new structure.
_astar_grid.set_point_solid(grid_coords, true)
## Queries the shortest path for an AI agent.
func get_ai_path(start: Vector2i, target: Vector2i) -> Array[Vector2i]:
return _astar_grid.get_id_path(start, target)3. FastNoiseLite Biome-Generation Pattern
Procedural world generation requires organic transitions between ecosystems. Use FastNoiseLite to generate a noise map and map its gradients (-1.0 to 1.0) to specific biomes.
class_name BiomeGenerator extends Node
var _biome_noise: FastNoiseLite
func _ready() -> void:
_biome_noise = FastNoiseLite.new()
_biome_noise.seed = randi()
_biome_noise.fractal_type = FastNoiseLite.FRACTAL_FBM
_biome_noise.fractal_octaves = 5
_biome_noise.frequency = 0.05
## Samples the noise at a specific coordinate to determine the biome type.
func get_biome_at_coordinate(x: float, y: float) -> String:
var noise_val: float = _biome_noise.get_noise_2d(x, y)
if noise_val < -0.25:
return "Deep_Ocean"
elif noise_val < 0.0:
return "Shallow_Water"
elif noise_val < 0.4:
return "Forest"
else:
return "Mountain"- Master Skill: godot-master
extends Node
class_name CraftingRecipeProcessor
## Expert Crafting System (Godot 4.6).
## Two-pass validation and consumption logic for item recipes.
@export var inventory: ModularInventoryController
func craft(recipe_res: Resource) -> bool:
# 1. Validation: Do we have all ingredients?
for item_path in recipe_res.ingredients:
var req = recipe_res.ingredients[item_path]
if not _has_item(item_path, req): return false
# 2. Consumption: Deduct ingredients
for item_path in recipe_res.ingredients:
_consume_item(item_path, recipe_res.ingredients[item_path])
# 3. Output: Add result to inventory
var output = ResourceLoader.load(recipe_res.output_path)
inventory.add_item(output, 1)
return true
func _has_item(path: String, amt: int) -> bool: return true # Implementation logic
func _consume_item(path: String, amt: int) -> void: pass # Implementation logic
## [SKILL NOTICE]: Perform a full validation pass BEFORE consuming any
## resources to prevent partial-crafting bugs.
# skills/genre-survival/scripts/interactable.gd
extends Area3D
## Interactable Base Class (Expert Pattern)
## Standardizes interaction prompt and behavior.
class_name Interactable
@export var prompt_message: String = "Interact"
@export var one_shot: bool = false
func interact(user: Node) -> void:
_on_interact(user)
if one_shot:
queue_free()
func _on_interact(user: Node) -> void:
print("Interacted with %s by %s" % [name, user.name])
# Override this in subclasses
# e.g. Add item to inventory
## EXPERT USAGE:
## Extend this script (e.g. PickupItem.gd).
## Player RayCast checks for 'Interactable' class.
# skills/genre-survival/scripts/inventory_data.gd
class_name InventoryData
extends Resource
## Inventory Data (Expert Pattern)
## Resource-based inventory system compatible with Save/Load.
signal inventory_updated(slot_index: int)
@export var slots: Array[InventorySlotData] = []
func _init(num_slots: int = 20) -> void:
slots.resize(num_slots)
for i in range(num_slots):
slots[i] = InventorySlotData.new()
func add_item(item: Resource, amount: int) -> int:
var remaining = amount
# 1. Stack with existing
for i in range(slots.size()):
if remaining <= 0: break
var slot = slots[i]
if slot.item == item and slot.count < slot.max_stack:
var space = slot.max_stack - slot.count
var to_add = min(remaining, space)
slot.count += to_add
remaining -= to_add
inventory_updated.emit(i)
# 2. Add to empty
for i in range(slots.size()):
if remaining <= 0: break
var slot = slots[i]
if slot.item == null:
slot.item = item
var to_add = min(remaining, slot.max_stack) # Assuming item has specific max stack info elsewhere
slot.count = to_add
remaining -= to_add
inventory_updated.emit(i)
return remaining
# Inner Class for Slot cannot be exported strictly as resource in same file in 4.x usually
# But for simplicity in this pattern we define usage.
# Best practice: Separate file for SlotData.
# Here we assume InventorySlotData is a known class or we use Dictionary if simple.
# For this script, we'll assume InventorySlotData is defined below or externally.
## EXPERT USAGE:
## Create as .tres for default loadouts.
## Use add_item returns to handle "Inventory Full".
# skills/genre-survival/scripts/inventory_slot_data.gd
class_name InventorySlotData
extends Resource
## Inventory Slot Data (Expert Pattern)
## Separate resource for individual slots to allow easy serialization.
@export var item: Resource # Reference to ItemDefinition
@export var count: int = 0
@export var max_stack: int = 64 # Should theoretically come from Item Resource
func can_stack_with(other_slot: InventorySlotData) -> bool:
return item == other_slot.item and item != null and count < max_stack
## EXPERT USAGE:
## Used internally by InventoryData.
# skills/genre-survival/code/inventory_slot_resource.gd
extends Resource
class_name InventorySlot
## Survival Inventory Expert Pattern
## Uses Resources for type-safety and modularity.
@export var item_id: String = ""
@export var quantity: int = 0
@export var max_stack: int = 99
@export var item_icon: Texture2D
@export var metadata: Dictionary = {} # Store durability, mods, etc.
func can_add(amount: int) -> bool:
return (quantity + amount) <= max_stack
func add(amount: int) -> void:
quantity += amount
func use() -> bool:
if quantity > 0:
quantity -= 1
return true
return false
## EXPERT NOTE:
## NEVER use a simple 'Dictionary' [id, count] for survival inventories.
## Using a 'Resource' allows each item to store unique state (Durability,
## Custom Names, Enchantments) and enables easy use of the Inspector
## for balancing.
## For 'genre-survival', implement a 'Weighted Inventory' system where the
## total weight of all Slot resources affects the player's move speed.
extends Node
class_name ModularInventoryController
## Expert Inventory System (Godot 4.6).
## Uses ItemResources for data and InventorySlots for state tracking.
var slots: Array[InventorySlot] = []
class InventorySlot extends RefCounted:
var item: Resource # ItemResource
var amount: int = 0
func _init(i, a): item = i; amount = a
func add_item(item_res: Resource, amount: int) -> void:
# 1. Merge into existing slots
for slot in slots:
if slot.item == item_res and slot.amount < item_res.max_stack:
var can_take = item_res.max_stack - slot.amount
var take = mini(can_take, amount)
slot.amount += take
amount -= take
if amount <= 0: return
# 2. Add as new slots
while amount > 0:
var take = mini(item_res.max_stack, amount)
slots.append(InventorySlot.new(item_res, take))
amount -= take
## [SKILL NOTICE]: Use 'ItemResource' files for static data and
## 'InventorySlot' objects for items currently in the bag to avoid
## modifying shared resource files during gameplay.
extends Node
class_name StatusDepletionManager
## Expert Status Management (Godot 4.6).
## Continuous depletion of Hunger, Thirst, and Health using physics delta.
var stats: Dictionary = {
"hunger": {"val": 100.0, "max": 100.0, "rate": 0.5},
"thirst": {"val": 100.0, "max": 100.0, "rate": 0.8}
}
func _physics_process(delta: float) -> void:
for id in stats:
var s = stats[id]
# Expert Pattern: Frame-independent reduction
s.val = clamp(s.val - (s.rate * delta), 0.0, s.max)
if s.val <= 0: _on_stat_empty(id)
func _on_stat_empty(id: String) -> void:
# Trigger starvation/dehydration damage
pass
## [SKILL NOTICE]: Use '_physics_process(delta)' for continuous depletion
## instead of Timers for a smoother, frame-independent survival feel.
# survival_patterns.gd
extends Node
# 1. Time-Independent Decay
# EXPERT NOTE: Multiply decay rates by delta to ensure consistent behavior across different frame rates.
func process_survival_vitals(delta: float, decay_rate: float) -> void:
# thirst -= decay_rate * delta
pass
# 2. Environment Lighting Tween (Day/Night)
# EXPERT NOTE: Use interpolation to smoothly transition world lighting for atmospheric immersion.
func transition_to_night(env: Environment) -> void:
var tween := create_tween()
tween.tween_property(env, "ambient_light_energy", 0.1, 10.0)
# 3. MultiMeshInstance for Optimized Forests/Nature
# EXPERT NOTE: Efficiently draw thousands of static assets like trees or rocks in a single call.
func populate_nature(mm: MultiMesh, transforms: Array[Transform3D]) -> void:
for i in transforms.size():
mm.set_instance_transform(i, transforms[i])
# 4. Deep Duplication of Item Resources
# EXPERT NOTE: Prevent shared reference bugs (e.g., all axes breaking at once) by duplicating resources upon instance.
func initialize_item_stats(base_stats: Resource) -> Resource:
return base_stats.duplicate(true) # Deep duplicate
# 5. Asynchronous World Chunk Loading
# EXPERT NOTE: Stream persistent world data on background threads to prevent exploration hitches.
func load_world_chunk(path: String) -> void:
ResourceLoader.load_threaded_request(path)
# 6. GridMap Snapping for Base Building
# EXPERT NOTE: Correctly align player structures to a physical world grid for building systems.
func get_snapped_pos(grid: GridMap, world_pos: Vector3) -> Vector3:
var cell := grid.local_to_map(world_pos)
return grid.map_to_local(cell)
# 7. ConfigFile for Persistent Player Data
# EXPERT NOTE: Ideal for saving lightweight persistent options or simple unlocked recipes.
func save_unlocked_recipes(recipes: Array[StringName]) -> void:
var config := ConfigFile.new()
config.set_value("Player", "unlocked", recipes)
config.save("user://progression.cfg")
# 8. Functional Inventory Filtering
# EXPERT NOTE: Use built-in filter method for fast searching of inventory arrays.
func get_edible_items(inventory: Array) -> Array:
return inventory.filter(func(item): return item.get(&"is_edible") == true)
# 9. Persistent Entity Save Extraction
# EXPERT NOTE: Map all "Persist" group nodes to a dictionary for simple serialization.
func collect_world_state() -> Array[Dictionary]:
return get_tree().get_nodes_in_group(&"Persist").map(func(n): return n.call(&"save"))
# 10. Physics Body Freeing Wrapper
# EXPERT NOTE: Always use queue_free() for nodes involved in physics to avoid immediate memory corruption.
func safely_remove_entity(entity: Node) -> void:
if entity is Node:
entity.queue_free()