All skills
thedivergentai avatar

/godot-genre-horror

@9d6e91e

Expert blueprint for horror games: sawtooth tension pacing, Director macro-AI, sensory predator AI, sanity/stress FX, and scarcity loops. Use when building psychological/survival horror, dual-brain stalker AI (cheating Director + honest LoS/sound), flashlight/fog atmosphere, or safe-room saves. Keywords: horror_game, tension_pacing, director_system, sensory_perception, sanity_system, volumetric_fog, AI_reaction_time.

Use this Skill: https://skilld.dev/gh/thedivergentai/gd-agentic-skills/godot-genre-horror

This session only. Nothing lands on disk.

referencesexpert-horror-patterns.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Expert patterns (load on demand)

MANDATORY when implementing beyond Golden Path / Decision Trees. Do not paste into SKILL.md or scenes from memory.

Architecture Overview

1. The Director System (Macro AI)

Controls the pacing of the game to prevent constant exhaustion.

# director.gd
extends Node

enum TensionState { BUILDUP, PEAK, RELIEF, QUIET }
var current_tension: float = 0.0
var player_stress_level: float = 0.0

func _process(delta: float) -> void:
    match current_tension_state:
        TensionState.BUILDUP:
            current_tension += 0.5 * delta
            if current_tension > 75.0:
                 trigger_event()
        TensionState.RELIEF:
            current_tension -= 2.0 * delta

func trigger_event() -> void:
    # Hints the Monster AI to check a room NEAR the player, not ON the player
    monster_ai.investigate_area(player.global_position + Vector3(randf(), 0, randf()) * 10)

2. Sensory Perception (Micro AI)

The monster's actual senses.

# sensory_component.gd
extends Area3D

signal sound_heard(position: Vector3, volume: float)
signal player_spotted(position: Vector3)

func check_vision(target: Node3D) -> bool:
    var space_state = get_world_3d().direct_space_state
    var query = PhysicsRayQueryParameters3D.create(global_position, target.global_position)
    var result = space_state.intersect_ray(query)
    
    if result and result.collider == target:
        return true
    return false

3. Sanity / Stress System

Distorting the world based on fear.

# sanity_manager.gd
func update_sanity(amount: float) -> void:
    current_sanity = clamp(current_sanity + amount, 0.0, 100.0)
    # Effect: Camera Shake
    camera_shake_intensity = (100.0 - current_sanity) * 0.01
    # Effect: Audio Distortion
    audio_bus.get_effect(0).drive = (100.0 - current_sanity) * 0.05

Key Mechanics Implementation

Pacing (The Sawtooth Wave)

Horror needs peaks and valleys.

  1. Safety: Save room.
  2. Unease: Strange noise, lights flicker.
  3. Dread: Monster is known to be close.
  4. Terror: Chase sequence / Combat.
  5. Relief: Escape to Safety.

The "Dual Brain" AI

  • Director (All-knowing): Cheats to keep the alien relevant (teleports it closer if far away, guides it to player's general area).
  • Alien (Senses only): Honest AI. Must actually see/hear the player to attack.

3. Hiding-Spot Metadata System

Use decoupled Object metadata so AI can query state without knowing the class.

# hiding_spot.gd
func _ready():
    add_to_group("hiding_spots")
    set_meta("is_occupied", false)

# predator_ai.gd
func search_hiding_spots():
    for spot in get_tree().get_nodes_in_group("hiding_spots"):
        if spot.get_meta("is_occupied"):
            investigate(spot.global_position)

4. Adaptive Audio (Stress Muffling)

Dynamic low-pass filtering via AudioServer.

# audio_stress_manager.gd
func update_stress(fear_level: float):
    # Enable LPF effect on Master bus (index 0) if fear is high
    AudioServer.set_bus_effect_enabled(0, 0, fear_level > 0.5)
    # Attenuate volume linearly
    AudioServer.set_bus_volume_linear(0, 1.0 - (fear_level * 0.4))

5. Safe-Room Multithreaded Save

Use Thread and Mutex to prevent frame drops during checkpoint saves.

# safe_room.gd
var _save_thread: Thread = Thread.new()
var _mutex: Mutex = Mutex.new()

func trigger_save(data: Dictionary):
    _mutex.lock()
    if not _save_thread.is_alive():
        _save_thread.start(_do_save.bind(data.duplicate(true)))
    _mutex.unlock()

func _do_save(data):
    var file = FileAccess.open("user://save.dat", FileAccess.WRITE)
    file.store_var(data)
    file.close()

Godot-Specific Tips

  • Volumetric Fog: Use WorldEnvironment -> VolumetricFog for instant atmosphere. Animate density for dynamic dread.
  • Light Occluder 2D: For 2D horror, shadow casting is essential.
  • AudioBus: Use Reverb and LowPassFilter on the Master bus, controlled by scripts, to simulate "muffled" hearing when scared or hiding.
  • AnimationTree: Use blend spaces to smooth transitions between "Sneak", "Walk", and "Run" animations.

Common Pitfalls

  1. Constant Tension: Player gets numb. Fix: Enforce "Relief" periods where nothing happens.
  2. Frustrating AI: AI sees player instantly. Fix: Give AI a "reaction time" or "suspicion meter" before full aggro.
  3. Too Dark: Player can't see anything. Fix: Darkness should obscure details, not navigation. Use rim lighting or a weak flashlight.

Source: SKILL.md on GitHub

1 warning16d4 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides a comprehensive set of Godot game development patterns and scripts for horror game mechanics. No malicious patterns, data exfiltration, or unauthorized command executions were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    4/4 files flagged

Signed by skilld at 9d6e91e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 weeks ago.

Activeupdated 2 months ago

README badge

README badge for thedivergentai/gd-agentic-skills/godot-genre-horror