game.audio.sfx
Play a one-shot from anywhere on the hill.
local Sfx = require("game.audio.sfx")
Sfx.play(clipRef) -- flat, non-spatial
Sfx.play(clipRef, { pos = { x, y, z }, volume = 0.7 }) -- out on the hill
Sfx.play(clipRef, { pitch = 1, jitter = 0.12 }) -- a run that is not a machine
Sfx.ui("confirm") -- the menu's own set
It spawns a temporary entity carrying an Audio component, lets it sound, and
despawns it after ttl seconds. Pass pos for a spatial source, heard from
the AudioListener on the CameraRig. Resolve your clip through a literal
identity so the reference is pinned when this world is installed elsewhere.
Three things every caller gets
A voice budget. Below a reserve of free voices a low-priority one-shot is
dropped rather than stealing the narrator's. priority 0 is set dressing, 1
is the default, 2 survives a crowded mix, 3 always plays.
A collapse window. Ten motes caught in one frame is one sound, not ten
stacked copies 6 dB louder than anything else in the mix. The same clip asked
for again inside collapse seconds (35 ms by default) is dropped. Pass a
longer window for a sound that should never double up, or priority = 3 to
opt out.
Pitch jitter. jitter spreads repeats of one clip either side of their
pitch, so a run of them reads as a hill rather than a loop.
Options
pos, volume, pitch, jitter, maxDistance, channel, ttl, name,
priority, collapse, looping.
channel is one of sfx / ui / ambient / music / voice — the names
the mix knows. A source naming anything else plays at unity, which is a sound
nobody can turn down, so an unknown name falls back to sfx.
The menu's set
Sfx.ui(name) plays one of click / move / confirm / back / deny —
small struck-glass sounds, because the lantern is glass and brass and so is
the menu. Non-spatial, on the ui channel, and high enough priority to get
through a crowded mix.
Sfx.stopAll() drops every one-shot still sounding, so a hent that started a
frame before the round ended does not carry into the end card.
Scoped to this part · feeds back into the world's score.