Summary
AudioSource is the Unity component that plays audio. It is attached to a GameObject and references an AudioClip asset. For sound effects, the primary method is PlayOneShot, which plays a clip once without interrupting other sounds already playing on the same source. For background music, AudioSource.Play() combined with loop = true is standard. For transient world-positioned sounds (a coin collected, an enemy defeated), the static AudioSource.PlayClipAtPoint plays at a location without requiring an AudioSource on the emitting object.
Key ideas
AudioSource.Play() — plays the assigned clip from the beginning. If called again while playing, it restarts. Use for background music, ambient loops, and single persistent sounds.
AudioSource.PlayOneShot(clip) — plays the given clip once without replacing any currently playing sound on that source. Multiple calls layer on top of each other. Use for sound effects that may fire in rapid succession (coins, footsteps, hits).
AudioSource.PlayClipAtPoint(clip, worldPosition) — static method; no AudioSource component needed on the caller. Spawns a temporary GameObject at the given world position, plays the clip, then destroys itself. Use for pickups, explosions, and any transient world sound.
Looping background music: Set clip, loop = true, volume, then call Play(). Use a dedicated AudioSource component for music — separate from the one used for SFX — so volume can be controlled independently.
AudioSource.pitch — playback speed and pitch together (1 is normal; the Manual calls it the “Amount of change in pitch due to slowdown/speed up of the Audio Clip”, Unity Technologies, Unity Manual: Audio Source component reference). Small random values (0.9–1.1) are a cheap way to vary repeated SFX such as footsteps. It is not a tempo control for music: raising it makes the music faster and higher in key at once. To change musical tempo, switch on a bar line to a cue written at the new tempo (see “Changing tempo when combat starts” in unity-adaptive-music-crossfade).
AudioListener.volume — a static property (0 to 1) that scales all audio in the game. Setting it to 0f mutes everything; 1f is full volume.
[Range(0f, 1f)] — an Inspector attribute that displays a float field as a slider constrained to the given range. Useful for volume controls.
Mathf.Clamp01(value) — shorthand for Mathf.Clamp(value, 0f, 1f). Use when accepting a volume value from outside code.
In practice
Looping background music:
[Header("Music")]
[SerializeField] private AudioSource musicSource;
[SerializeField] private AudioClip mainTheme;
[SerializeField] [Range(0f, 1f)] private float musicVolume = 0.4f;
private void StartMusic()
{
if (musicSource == null || mainTheme == null) return;
musicSource.clip = mainTheme;
musicSource.loop = true;
musicSource.volume = musicVolume;
musicSource.Play();
}SFX with PlayOneShot (layers, does not interrupt):
[Header("SFX")]
[SerializeField] private AudioSource sfxSource;
[SerializeField] private AudioClip coinClip;
[SerializeField] private AudioClip hitClip;
private void PlaySFX(AudioClip clip)
{
if (clip == null || sfxSource == null) return;
sfxSource.PlayOneShot(clip); // layered — rapid calls don't interrupt
}
// Usage
PlaySFX(coinClip);
PlaySFX(hitClip);PlayClipAtPoint — world-positioned sound, no AudioSource needed:
public void OnCoinCollected(Vector3 worldPosition)
{
if (coinClip != null)
AudioSource.PlayClipAtPoint(coinClip, worldPosition);
}Read this method as an event response, not as an audio loop. Something else in the game detects the coin collection, then passes the coin’s world position into OnCoinCollected. The method checks whether a clip was assigned, plays the sound at that position, and then returns. There is no Update here because sound effects are triggered by game events, not checked every frame.
Global mute toggle:
private bool isMuted = false;
public void ToggleMute()
{
isMuted = !isMuted;
AudioListener.volume = isMuted ? 0f : 1f;
}Adjustable music volume:
public void SetMusicVolume(float volume)
{
musicVolume = Mathf.Clamp01(volume);
if (musicSource != null)
musicSource.volume = musicVolume;
}Crossfading music between game states
To change music when the game state changes (exploring → combat), don’t call Play() with a new clip on the one music source. That cuts the old track off instantly. Use two music AudioSources instead: start the new clip on the idle source at volume 0, then fade one down and the other up over a second or two in a coroutine. An equal-power curve (Mathf.Cos / Mathf.Sin of t * Mathf.PI * 0.5f) avoids a loudness dip halfway through. Use Time.unscaledDeltaTime so the fade still finishes while the game is paused.
For changes that must land on the beat, schedule the new clip with AudioSource.PlayScheduled(AudioSettings.dspTime + …) on the next bar line. For mixes across many sources, use AudioMixer snapshots and AudioMixerSnapshot.TransitionTo(seconds). Code for all three, plus music layers (stems) and a checklist for when FMOD or Wwise is worth it, is in unity-adaptive-music-crossfade.
Recommended setup
For a typical 2D game:
- Music AudioSource — on the FeedbackManager or a dedicated MusicManager.
Loop = true,Play On Awake = trueoptional. Volume set in script. - SFX AudioSource — same GameObject as above, or on the player. Used with
PlayOneShotonly. Clip field left empty. - Transient world sounds — handled by
AudioSource.PlayClipAtPoint; no component required on pickups or enemies.
There is no need for a separate AudioSource on every pickup or hazard. Centralising sound playback in a FeedbackManager keeps scene setup simple and makes volume control straightforward.
Debugging audio setup
Most beginner audio failures are setup failures:
| Symptom | Likely cause | First check |
|---|---|---|
| No sound at all | Missing AudioListener | Check the Main Camera has an AudioListener |
| Music does not start | musicSource or mainTheme is unassigned | Check the FeedbackManager Inspector |
| Coin sound cuts itself off | Using Play() for repeated SFX | Use PlayOneShot |
| Sound plays at start before event | Play On Awake enabled | Untick it on SFX sources |
| Volume slider behaves strangely | Value not clamped | Use Mathf.Clamp01 before assigning volume |
Gotchas
AudioSource.Play()restarts the clip from the beginning each call. If a coin collection sound is called multiple times per second, only the last call will be audible. UsePlayOneShotfor any effect that can trigger rapidly.PlayClipAtPointcreates a temporary GameObject. It is self-cleaning, but generates a small allocation per call. Acceptable for occasional events; avoid using it every frame.- If no
AudioListenerexists in the scene (usually on the Main Camera), Unity logs a warning and no sound plays. Check the Camera has anAudioListenercomponent. AudioSource.PlayOneShotdoes not support volume scaling beyond the source’s ownvolumeproperty. To play a specific clip at a different volume, pass the volume as the second argument:sfxSource.PlayOneShot(clip, 0.5f).
Worked example
The beginner 2D route keeps the sound on the coin itself, which shows the trade-off with the central setup recommended above:
- CoinPickupFeedback.cs — on pickup, hides the sprite, plays a particle burst and the coin’s own AudioSource, then destroys the coin after 0.5 seconds. Because the AudioSource is destroyed with the coin, any clip longer than that delay is cut off;
AudioSource.PlayClipAtPointor a central SFX source avoids this.
Practice
Build a small AudioManager for a 2D scene:
- a looping music track on one AudioSource, started from
Start, with volume set by a[Range(0f, 1f)]field - a second AudioSource for sound effects, played only with
PlayOneShot - Space plays a coin sound; M toggles global mute; Up/Down raise and lower music volume through a
SetMusicVolumemethod that clamps its input
Success test:
- the music loops and the SFX source does not play anything on start
- tapping Space quickly layers the coin sound instead of restarting it
- M silences music and effects together, and pressing it again restores them
- holding Up never pushes the music volume above
1
Extension:
- add a second music source and crossfade from an “explore” track to a “combat” track over two seconds using the approach in “Crossfading music between game states” and unity-adaptive-music-crossfade
Self-test
- Which method should play a coin sound that may fire several times a second,
Play()orPlayOneShot? Why? - How do you set up looping background music on an AudioSource?
- What does
AudioSource.PlayClipAtPointdo, and what does it need on the calling object? - How do you mute every sound in the game at once?
- A scene plays no sound at all. What is the first thing to check?
- Why use two music AudioSources to change track when the game state changes?
Answers
PlayOneShot, because it layers clips without interrupting the one already playing;Play()restarts the clip, so only the last call is heard.- Assign the
clip, setloop = trueand thevolume, then callPlay(), ideally on an AudioSource used only for music. - It plays a clip at a world position by creating a temporary GameObject that cleans itself up; the caller needs no AudioSource.
- Set
AudioListener.volume = 0f(and back to1fto unmute). - Whether the scene has an
AudioListener, usually on the Main Camera. - Calling
Play()with a new clip on one source cuts the old track off instantly. With two sources, the new clip starts at volume 0 and one fades down while the other fades up.
Related
- unity-particle-system-scripting — particles and audio are typically triggered together as game feedback
- unity-inspector-references — wiring AudioSource and AudioClip references
- monobehaviour-lifecycle —
Startfor initialising music;Updatefor volume fades if needed - unity-adaptive-music-crossfade — crossfades, mixer snapshots, bar-aligned switching and stem layers for adaptive music
- audio-middleware-overview — where teams move when simple AudioSource playback is no longer enough for adaptive music or runtime mixing