Loading...
Loading...
Expert blueprint for horror games including tension pacing (sawtooth wave: buildup/peak/relief), Director system (macro AI controlling pacing), sensory AI (vision/sound detection), sanity/stress systems (camera shake, audio distortion), lighting atmosphere (volumetric fog, dynamic shadows), and "dual brain" AI (cheating director + honest senses). Use for psychological horror, survival horror, or atmospheric games. Trigger keywords: horror_game, tension_pacing, director_system, sensory_perception, sanity_system, volumetric_fog, AI_reaction_time.
npx skill4agent add thedivergentai/gd-agentic-skills godot-genre-horrorPhysicsDirectSpaceState3D.intersect_ray()VisibleOnScreenNotifier3DDictionary[StringName, Resource]Resourceduplicate(true)WorkerThreadPoolStringNameis_equal_approx()SCREEN_TEXTUREsampler2Dhint_screen_texturevisibility_rangeTweenload()ResourceLoader.load_threaded_request()| Phase | Skills | Purpose |
|---|---|---|
| 1. Atmosphere | | Volumetric fog, dynamic shadows, spatial audio |
| 2. AI | | Hunter AI, sensory perception |
| 3. Player | | Leaning, hiding, slow movement |
| 4. Scarcity | | Limited battery, ammo, health |
| 5. Logic | | The "Director" system controlling pacing |
# 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)# 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# 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.05WorldEnvironmentVolumetricFogdensityReverbLowPassFilter