Audio Systems¶
Core Components¶
AudioSource¶
The primary component for playing sounds:
[SerializeField] private AudioSource _audioSource;
[SerializeField] private AudioClip _shootSound;
public void PlayShoot()
{
// PlayOneShot allows overlapping sounds from the same source
_audioSource.PlayOneShot(_shootSound, 0.8f);
}
Key properties:
- clip: The default AudioClip
- volume: 0.0 to 1.0
- pitch: Playback speed (1.0 = normal). Randomize slightly for variety: Random.Range(0.9f, 1.1f)
- spatialBlend: 0 = 2D (UI, music), 1 = 3D (world sounds)
- loop: Enable for ambient sounds and music
AudioListener¶
Receives all audio in the scene. Rules: - Exactly one active AudioListener per scene - Usually attached to the main camera - 3D sound positioning is relative to the AudioListener
AudioMixer¶
AudioMixer provides professional audio routing, effects, and volume control.
Groups¶
Create a hierarchy of mixer groups:
Exposed Parameters¶
Expose mixer parameters for script control:
[SerializeField] private AudioMixer _mixer;
public void SetMusicVolume(float normalizedValue)
{
// Convert 0-1 slider to decibels (-80 to 0)
float dB = normalizedValue > 0.001f
? Mathf.Log10(normalizedValue) * 20f
: -80f;
_mixer.SetFloat("MusicVolume", dB);
}
Snapshots¶
Pre-configure mixer states for different game contexts: - Default: normal gameplay mix - Paused: duck SFX, lower music - Underwater: low-pass filter on all groups - Menu: music only, SFX muted
Transition between snapshots: snapshot.TransitionTo(0.5f).
Effects¶
Built-in mixer effects: Reverb, Echo, Chorus, Flange, Distortion, Low Pass, High Pass, Compressor.
3D Spatial Audio¶
Configure AudioSource for spatial audio: - Spatial Blend: Set to 1.0 for full 3D positioning - Min/Max Distance: Controls volume rolloff range - Rolloff: Logarithmic (realistic), Linear (predictable), or Custom curve - Doppler Level: Pitch shift for moving sources (0 = off) - Spread: Stereo width at the listener (0 = point source, 360 = surround)
Audio Pooling¶
For sounds that play frequently (footsteps, impacts, bullets):
public class AudioPool : MonoBehaviour
{
[SerializeField] private int _poolSize = 10;
private AudioSource[] _sources;
private int _nextIndex;
private void Awake()
{
_sources = new AudioSource[_poolSize];
for (int i = 0; i < _poolSize; i++)
{
_sources[i] = gameObject.AddComponent<AudioSource>();
_sources[i].playOnAwake = false;
}
}
public void Play(AudioClip clip, float volume = 1f)
{
_sources[_nextIndex].PlayOneShot(clip, volume);
_nextIndex = (_nextIndex + 1) % _poolSize;
}
}
Music Management¶
Crossfading¶
private async Awaitable CrossfadeAsync(AudioSource from, AudioSource to, float duration)
{
to.volume = 0f;
to.Play();
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = elapsed / duration;
from.volume = 1f - t;
to.volume = t;
await Awaitable.NextFrameAsync();
}
from.Stop();
from.volume = 1f;
}
Layered Music¶
Play multiple tracks simultaneously and blend between them for adaptive music: - Base layer: ambient melody (always playing) - Action layer: percussion (fade in during combat) - Tension layer: strings (fade in during stealth)
AudioClip Loading¶
- Decompress On Load: Small, frequently used clips (UI clicks, footsteps). Fastest playback, uses more memory.
- Compressed In Memory: Medium clips (SFX). Good balance of memory and CPU.
- Streaming: Large clips (music, ambient loops). Low memory, slight CPU cost.
Common AudioManager Pattern¶
See snippets/csharp/singleton-pattern.cs for the Singleton base. Build an AudioManager that centralizes playback, manages the mixer, and provides a simple API: