GameAudio
Every sound in Spooky Spook Spook. Lives on the `Game` systems root and talks to the rest of the game only through `game.rules` events. The AudioListener sits on the player's CameraRig (scene-owned), so spatial sounds are heard from the first-person eye.
GameAudio
Every sound in Spooky Spook Spook. Lives on the Game systems root and talks to the rest of the game only through game.rules events. The AudioListener sits on the player's CameraRig (scene-owned), so spatial sounds are heard from the first-person eye.
On the first gameplay frame it spawns runtime children under Game:
audio_music_a,audio_music_b— two looping music decks (channelmusic) that crossfade overcrossfadeSecondson everyphaseChanged.audio_sfx— the non-spatial SFX bus (channelsfx).audio_emitter_1..12— a pool of spatial emitters. Each is moved to an event'sposbefore a one-shot fires there.
Music per phase
| phase | track |
|---|---|
| title, won | music/title_theme |
| fight | music/fight_loop |
| ossuary, dead | music/ossuary_ambience (quieter on dead) |
| fight on wave >= R.WAVE_COUNT (the Grave-Golem) | music/boss_theme (re-checked on every waveStarted) |
Enemy voices
enemyHit and enemyKilled also play the kind's own vocal, spatial at pos, rate-limited to one per kind every 0.32 s (0.16 s for deaths):
ghoul → sfx/ghoul_moan, imp → sfx/imp_cackle, wisp → sfx/wisp_whisper, golem → sfx/golem_rumble.
Any enemy_golem_* child of Game also rumbles (low pitch, spatial) every 2.2 m it walks.
Player movement
Each fight frame GameAudio reads R.playerPos(). If R.stats().legs > 0 the player hears sfx/bone_step at a cadence that follows speed and leg count. A lone skull hears the looping sfx/skull_roll bed on Game/audio_roll, whose volume and pitch follow rolling speed.
Headbutt
playerAttack kind=headbutt → sfx/headbutt plus a soft low whoosh. enemyHit with attack=headbutt plays sfx/headbutt at the enemy, replacing bone_crunch.
SFX per event
| event | clip | spatial |
|---|---|---|
| enemyHit | sfx/bone_crunch (pitch by kind, golem lower) | yes, at pos |
| enemyKilled | sfx/enemy_pop (pitch by kind) | yes, at pos |
| boneDropped | sfx/bone_detach (high, quiet) | yes, at pos |
| boneCollected | sfx/bone_chime (pitch rises with rarity) | no |
| boneAttached | sfx/bone_click | no |
| boneDetached | sfx/bone_detach | no |
| waveStarted | sfx/wave_horn | no |
| waveCleared | sfx/wave_clear | no |
| playerHurt | sfx/player_hurt | no |
| playerDied | sfx/player_death | no |
| phaseChanged → won | sfx/win_fanfare | no |
| playerAttack | bolt → sfx/magic_bolt, bite → bone_crunch (high), else sfx/attack_whoosh | no |
| uiClick | sfx/ui_click | no |
Identical clips that fire within 45 ms of each other play once, so a burst of hits in one frame does not stack.
Provider
R.call("playSound", name, pos?, opts?) plays any of the clip keys above (bone_crunch, enemy_pop, ...). pos is {x,y,z} and makes the sound spatial. opts is { volume, pitch, jitter }.
Public fields
musicVolume(0.55): the level music settles at.sfxVolume(0.9): a multiplier on every SFX.crossfadeSeconds(1.6): how long a phase crossfade takes.spatialRange(45 m): the maxDistance for positioned sounds.
Methods
:play(name, pos?): fires one clip.:status(): returns{ track, built, decks = { {track, vol, target} } }.
Scoped to this part · feeds back into the world's score.