arcade2d
Class

AudioSource

audio/audio-source.ts:72

Plays short, one-shot sound effects from a WorldObject.

Attach an AudioSource to any object that needs to emit SFX — a player who fires bullets, a door that creaks, a wall that takes damage. Each call to AudioSource.play spawns a fresh, fire-and-forget AudioInstance routed through the AudioEngine's SFX bus, so several voices from the same source can overlap freely (the burst of an automatic weapon, two shots in quick succession).

What "source" means

AudioSource is the host-component analogue of the renderer's Sprite: a thin behavioural component bound to a WorldObject that exposes a tidy play() / stop() surface and hides the audio-graph bookkeeping. The component holds:

  • A default asset — the clip most calls play, often the only one.
  • Default volume and pan — applied to each voice unless the call site overrides them in AudioSourcePlayOptions.
  • The set of voices it has spawned but not yet finished, so it can AudioSource.stop them in bulk or clean them up when the host WorldObject is destroyed.

Spawn vs play

Unlike Music, voices are spawned per-play, not held by the component. AudioSource.play returns the spawned AudioInstance for the rare caller that wants to fade or stop one voice specifically; most callers ignore the return value entirely.

Stereo positioning

AudioSource does not auto-position based on the host's world position — the engine's panning is a manual [-1, 1] knob, not a positional PannerNode model. If you want a sound to follow the host, set AudioSource.pan from your own controller (e.g. interpolate from host.position.x against the camera). A positional/PannerNode-based variant may land later.

Example

const player = world.createObject();
const shoot = game.assets.getAs('gunshot', AudioAsset);

player.addComponentFromFactory(
  'audio',
  (host) => new AudioSource(host, shoot, { volume: 0.6 }),
);

// Later, in the input handler:
player.getComponent<AudioSource>('audio').play();

Constructors

#
constructor(host: WorldObject, asset: null | AudioAsset, options: AudioSourceOptions): AudioSource

Parameters

Properties

#
enabled: boolean

Per-component gate on the three update hooks (onPreUpdate, onUpdate, onPostUpdate). When explicitly false, the engine skips all three for this component during the host's tick — useful for temporarily pausing behaviour (e.g. a freeze powerup) without removing the component and losing its internal state.

Does not gate onAdded or onDestroy; those always fire so a host can never end up with a half-attached component.

readonly #
host: WorldObject

The host this component is attached to. Stored read-only; subclasses access it as this.host directly, or through the tier-appropriate aliases (this.world, this.game) on the per-tier abstract bases.

Accessors

readonly #
activeVoiceCount: number

The number of voices this source currently has running. Useful for tests and for caps ("don't spawn more than four concurrent footsteps").

readonly #
asset: null | AudioAsset

The default AudioAsset this source plays, or null when the source was constructed without one.

readonly #
game: Game

The Game the host's world belongs to. Always non-null — the world's game field is a mandatory construction argument, not an option.

#
pan: number

Default stereo pan from -1 (left) to 1 (right) applied to each new voice. Setting this also re-targets currently-playing voices.

readonly #
playing: boolean

Whether this source has at least one voice currently advancing through its buffer (playing and unpaused). The aggregate counterpart to AudioInstance.playing.

#
volume: number

Default volume from 0 to 1 applied to each new voice. Setting this also re-targets any currently-playing voices spawned by this source — a single source pretends to be one continuous emitter even when it is actually a bag of one-shots.

readonly #
world: World

The World the host WorldObject lives in. Shorthand for this.host.world.

Methods

#
onAdded(_deps: Record): void

Lifecycle hook that is called when the component is added to the host object. Should not be called directly.

Parameters

  • _deps Record

Returns

void
#
onDestroy(): void

Stops and tears down every voice this source spawned when the host WorldObject is destroyed. The source itself owns no audio-graph nodes — each voice owns and disconnects its own gain/panner — so this is just a bulk AudioSource.stop.

Returns

void
#
onUpdate(_update: WorldUpdate, _deps: Record): void

Lifecycle hook for the main update phase. Called once per world tick, after every component's onPreUpdate and before any onPostUpdate.

Parameters

Returns

void
#
pause(): void

Pauses every voice this source currently has playing, each keeping its resume position; a later AudioSource.resume restarts them from where they paused. The aggregate counterpart to AudioInstance.pause, mirroring the per-voice surface up to the source. Voices that are not playing are left untouched.

Returns

void
#
play(options: AudioSourcePlayOptions): AudioInstance

Spawns a fresh playback voice and starts it. Each call produces an independent AudioInstance, so overlapping plays (rapid fire, footstep cadence, a triggered burst) layer naturally instead of cutting each other off.

The voice is registered internally so AudioSource.stop and onDestroy can shut it down in bulk, and unregistered automatically when the underlying source ends.

Looping voices never end on their own, so a voice started with { loop: true } stays registered (and counted in AudioSource.activeVoiceCount) until you AudioSource.stop the source or the host WorldObject is destroyed. Hold the returned AudioInstance if you need to stop one specific loop.

Parameters

Returns

AudioInstance

The spawned AudioInstance. Most callers ignore the return; reach for it when you want to fade or stop a specific voice.

Throws

EngineError with code ErrorCode.AUDIO_NO_SOURCE when no asset is supplied and the source has no default asset to fall back on.

#
resume(): void

Resumes every voice this source paused with AudioSource.pause, each from its saved position. Voices that are not paused (still playing, or already finished) are left untouched.

Returns

void
#
setAsset(asset: null | AudioAsset): void

Swap the default AudioAsset. Does not affect voices already playing — they keep playing the asset they were started with.

Parameters

Returns

void
#
stop(): void

Stops every voice this source is currently playing and tears each one down. Idempotent — calling on a source with no active voices is a no-op.

Returns

void
ESC