Week 11 — Tutorial

🔊 Sound Arena

Build a timed collection game with background music, pickup sound effects, spawn audio, spatial 3D sound, and a game-over jingle. You'll use free Asset Store audio packs and write scripts to trigger sounds from gameplay events.

1
Project & Asset Store Setup

You'll need a set of audio clips for this tutorial: a background music loop, a collectible pickup sound, a spawn sound, and a game-over jingle. We'll get these from the Unity Asset Store.

  1. Create a new 3D (Built-in Render Pipeline) project named SoundArena. Alternatively, create a new Scene in an existing project.
  2. Open the Asset Store in your browser at assetstore.unity.com. Log in with your Unity account.
  3. Search for a free sound effects pack. Suggested searches:
    • "Free Sound Effects Pack" by Olivier Girardot
    • "FREE Casual Game SFX Pack" by Dustyroom
    • "Universal Sound FX" (free version) by Imphenzia
    • Any free pack that includes: pickup/coin, impact/spawn, and a short music loop
  4. Click Add to My Assets, then open Unity and go to Window → Package Manager. Switch the dropdown to My Assets, find your pack, and click Download then Import.
  5. After import, browse the audio files in your Project window. Take note of which clips you'll use for:
    • 🎵 Music — a looping track (any calm or upbeat loop)
    • Pickup — a short chime or coin sound
    • 👾 Spawn — a whoosh, pop, or impact
    • 🏁 Game Over — a jingle, fail sound, or descending tone
No Asset Store access? You can use any .wav, .mp3, or .ogg files. Free sounds are available at freesound.org or mixkit.co. Download files and drag them into your Unity Project's Assets folder.
  • Audio pack imported into Unity
  • Identified clips for music, pickup, spawn, and game over
2
Scene Layout

Build the gameplay scene — a ground plane with a player, collectibles, and a spawner. This reuses what you built in Week 10's micro-tasks.

  1. Create a Plane at (0, 0, 0). Scale it to (2, 1, 2) so the arena is larger.
  2. Create a Cube at (0, 0.5, 0). Name it Player. Give it a blue Material. Add a Rigidbody component.
  3. Create a Sphere at (3, 0.5, 3). Name it Collectible. Scale to (0.5, 0.5, 0.5). Give it a yellow Material.
  4. On the Sphere's Collider, tick Is Trigger.
  5. Add the tag Collectible in Edit → Project Settings → Tags and Layers. Assign it to the Sphere.
  6. Drag the Sphere from Hierarchy into the Project window to create a Prefab. Delete the original from the scene.
  7. Create a Capsule. Give it a red Material. Create a Prefab from it. Delete the original. This is the enemy Prefab.
  8. Create an empty GameObject named Spawner at (0, 0, 0).
  9. Create an empty GameObject named GameManager.
  10. Add UI text elements: create GameObject → UI → Text - TextMeshPro twice — one for Score (top-left), one for Timer (top-right). Set default text to "Score: 0" and "30" respectively. If prompted, import TMP Essentials.
  11. Create a third TextMeshPro text centred on screen with text "Time's Up!", font size 60. Disable this GameObject (uncheck its checkbox).
AudioListener check Select the Main Camera in your Hierarchy and confirm it has an AudioListener component. This is added by default — do not remove it. Do not add AudioListener to any other object.
  • Ground plane, Player cube with Rigidbody
  • Collectible Prefab (trigger, tagged)
  • Enemy Prefab (red capsule)
  • UI: Score text, Timer text, Game Over text (disabled)
  • Main Camera has AudioListener
3
Background Music

Background music plays continuously from the moment the scene loads. It should loop, be 2D (heard at the same volume everywhere), and be quieter than sound effects so it doesn't drown them out.

  1. Create an empty GameObject named BackgroundMusic.
  2. Add an AudioSource component to it (Add Component → Audio → Audio Source).
  3. Drag your music AudioClip from the Project window into the AudioClip field on the AudioSource.
  4. Configure the AudioSource:
    • Play On Awake: ✅ Checked
    • Loop: ✅ Checked
    • Volume: 0.3 (keep it subtle)
    • Spatial Blend: 0 (fully 2D — heard everywhere equally)
  5. Press Play and verify the music starts immediately and loops continuously.
Why no script? For simple looping music, you don't need any code. The AudioSource component handles play-on-awake and looping entirely through Inspector settings. You'll add script control later when you need to stop the music on game over.
  • Music plays when scene starts
  • Music loops without gaps
  • Volume is subtle (not overpowering)
4
Player Movement (with Audio)

The player moves with WASD using physics. We'll also add an AudioSource to the player so it can play pickup and other sounds triggered by gameplay events.

  1. Add an AudioSource component to the Player object.
  2. On this AudioSource, uncheck Play On Awake (we'll trigger sounds from scripts). Set Spatial Blend to 0 (2D).
  3. Create a new C# script called PlayerMovement and attach it to the Player.
PlayerMovement.cs
using UnityEngine; public class PlayerMovement : MonoBehaviour { [SerializeField] private float speed = 6f; private Rigidbody rb; void Awake() { rb = GetComponent<Rigidbody>(); } void FixedUpdate() { float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); Vector3 movement = new Vector3(h, 0f, v); rb.MovePosition(rb.position + movement * speed * Time.fixedDeltaTime); } }
  • Player moves with WASD/arrow keys
  • Player has an AudioSource (Play On Awake off)
5
Collectible Pickup with Sound Effects

When the player picks up a collectible, a sound should play. We use PlayOneShot() because it allows multiple pickup sounds to overlap if the player collects rapidly.

  1. Create a new C# script called PlayerCollector and attach it to the Player.
  2. In the Inspector, drag your pickup AudioClip into the pickupSound field.
  3. Drag the Score TextMeshPro object into the scoreText field.
  4. Manually place 5–6 instances of the Collectible Prefab around the ground plane so you can test.
PlayerCollector.cs
using TMPro; using UnityEngine; public class PlayerCollector : MonoBehaviour { [SerializeField] private AudioClip pickupSound; [SerializeField] private TMP_Text scoreText; private AudioSource audioSource; private int score = 0; void Awake() { audioSource = GetComponent<AudioSource>(); } void OnTriggerEnter(Collider other) { if (other.CompareTag("Collectible")) { score++; scoreText.text = "Score: " + score; // Play the sound on the player's AudioSource audioSource.PlayOneShot(pickupSound); // Destroy the collectible object Destroy(other.gameObject); } } }
Why PlayOneShot instead of Play? Play() interrupts any sound currently playing on that AudioSource. If the player picks up two items quickly, the first sound would cut off. PlayOneShot() layers sounds on top of each other — both play to completion.
  • Collecting a sphere plays the pickup sound
  • Score updates on screen
  • Rapid pickups overlap sounds correctly
6
Enemy Spawner with Audio

Enemies spawn every 2 seconds at random positions. Each spawn plays a sound at the spawn location using AudioSource.PlayClipAtPoint() — a static method that creates a temporary AudioSource, plays the clip, then cleans itself up.

  1. Create a new C# script called EnemySpawner and attach it to the Spawner object.
  2. Drag the enemy Prefab into the enemyPrefab field in the Inspector.
  3. Drag your spawn AudioClip into the spawnSound field.
EnemySpawner.cs
using System.Collections; using UnityEngine; public class EnemySpawner : MonoBehaviour { [SerializeField] private GameObject enemyPrefab; [SerializeField] private AudioClip spawnSound; [SerializeField] private float spawnInterval = 2f; [SerializeField] private float spawnRange = 8f; void Start() { StartCoroutine(SpawnLoop()); } IEnumerator SpawnLoop() { while (true) { float x = Random.Range(-spawnRange, spawnRange); float z = Random.Range(-spawnRange, spawnRange); Vector3 spawnPos = new Vector3(x, 1f, z); Instantiate(enemyPrefab, spawnPos, Quaternion.identity); // Play sound at the spawn position AudioSource.PlayClipAtPoint(spawnSound, spawnPos); yield return new WaitForSeconds(spawnInterval); } } }
Why PlayClipAtPoint here? The Spawner object sits at the centre of the arena, but enemies spawn at random positions. PlayClipAtPoint() creates a temporary one-shot AudioSource at the exact spawn position. Later when you enable 3D spatial audio, the spawn sound will come from the correct direction.
  • Enemies spawn every 2 seconds at random positions
  • A sound plays at each spawn location
7
Timer & Game Over Audio

A 30-second countdown timer ticks down. When it hits zero, the game freezes, background music stops, and a game-over sound plays. This script controls the overall game state.

  1. Create a new C# script called GameTimer and attach it to GameManager.
  2. Add an AudioSource component to GameManager. Uncheck Play On Awake.
  3. In the Inspector, assign:
    • timerText — the Timer TMP text object
    • gameOverUI — the "Time's Up!" text GameObject
    • gameOverSound — your game-over AudioClip
    • backgroundMusic — the BackgroundMusic AudioSource (drag the BackgroundMusic object)
GameTimer.cs
using TMPro; using UnityEngine; public class GameTimer : MonoBehaviour { [SerializeField] private TMP_Text timerText; [SerializeField] private GameObject gameOverUI; [SerializeField] private AudioClip gameOverSound; [SerializeField] private AudioSource backgroundMusic; [SerializeField] private float startTime = 30f; private AudioSource audioSource; private float timeRemaining; private bool isGameOver = false; void Awake() { audioSource = GetComponent<AudioSource>(); } void Start() { timeRemaining = startTime; gameOverUI.SetActive(false); Time.timeScale = 1f; // Reset in case it was frozen } void Update() { if (isGameOver) return; timeRemaining -= Time.deltaTime; if (timeRemaining <= 0f) { timeRemaining = 0f; GameOver(); } timerText.text = Mathf.CeilToInt(timeRemaining).ToString(); } void GameOver() { isGameOver = true; gameOverUI.SetActive(true); // Stop the background music backgroundMusic.Stop(); // Play the game-over jingle audioSource.PlayOneShot(gameOverSound); // Freeze the game after a short delay // (so the game-over sound can still play) Invoke("FreezeGame", 0.1f); } void FreezeGame() { Time.timeScale = 0f; } }
Why not freeze immediately? Setting Time.timeScale = 0f immediately would prevent the game-over sound from playing because AudioSource timing depends on the game clock. We use Invoke() with a tiny 0.1s delay to let the audio system register the play command before freezing.
  • Timer counts down from 30
  • "Time's Up!" appears at zero
  • Background music stops on game over
  • Game over sound plays
  • Game freezes after the sound starts
8
3D Spatial Audio

Right now all sounds are 2D — they sound the same regardless of where the player is. Let's make the collectibles emit a subtle spatial hum so the player can hear them in 3D space.

  1. Open the Collectible Prefab (double-click it in the Project window).
  2. Add an AudioSource component to the Prefab.
  3. Assign a looping ambient sound (a hum, sparkle, or gentle tone) to the AudioClip field. If your audio pack doesn't have one, any short sound will do.
  4. Configure the AudioSource:
    • Play On Awake: ✅ Checked
    • Loop: ✅ Checked
    • Volume: 0.5
    • Spatial Blend: 1 (fully 3D)
  5. Expand the 3D Sound Settings section at the bottom of the AudioSource:
    • Min Distance: 1 (full volume within 1 unit)
    • Max Distance: 15 (silent beyond 15 units)
    • Volume Rolloff: Logarithmic (default — sounds natural)
  6. Save the Prefab and return to the scene.
  7. Place 5–6 collectibles around the arena at various distances from the player start position.
  8. Press Play and walk around — you should hear collectibles get louder as you approach and quieter as you move away. The sound should also pan left/right based on the collectible's position relative to the camera.
Test it properly Place a collectible far away (e.g., at position 12, 0.5, 12) and one close (at 2, 0.5, 2). When the game starts, you should hear the nearby one clearly and the distant one faintly. Walk toward the far one and listen for the volume increase. This is 3D spatial audio working.
  • Collectibles hum/glow audibly when nearby
  • Sound fades with distance
  • Sound pans left/right based on position
9
Build & Test

Run through the complete game and verify every audio element works together.

Final Audio Checklist Play the game from start to finish and confirm every item below. If any audio is missing or behaving incorrectly, check the relevant section above.
  • Background music starts immediately and loops
  • Player moves with WASD
  • Collecting a sphere plays a pickup sound and updates the score
  • Rapid pickups produce overlapping sounds (not cutting each other off)
  • Enemies spawn every 2 seconds with a spawn sound
  • Collectible hum is louder when nearby and quieter when far away
  • Timer counts down and freezes the game at 0
  • Background music stops on game over
  • Game-over sound plays before the game freezes
  • No console errors or warnings about multiple AudioListeners
Extension challenges (optional) If you finish early, try these: add a footstep sound that plays only while the player is moving, make enemies emit a 3D growl sound using an AudioSource on the enemy Prefab, or add a UI button click sound when the player presses a restart button.