At this point, you have a sound manager and many audio clips associated with it. You have some background music but no sound effects. In this tutorial, you’ll breathe some life into your game.
It’s amazing how sound can alter the tone and provide depth. Dead by Daylight, an asymmetrical multiplayer game, is a case study on excellent sound design. It is used mechanically to inform the player about certain in game events but it also provides a tense mood. The sounds effects are incredibly rich and detailed. Each sound effect, from the setting of a trap to the smashing of a palette makes the game a joy to both watch and play.
In your game, you’ll put sound to work and even add a power-up to make it even better to play.
Note: This tutorial is part of a collection that teaches Unity development from the ground up. You can read the entire series over here. This series is free and does not require any account creation. All assets are provided. If you find it useful, feel free to buy me a coffee.
Adding shooting sounds
In the Hierarchy, expand the SpaceMarine and select BobbleMarine-Body. In the Inspector, click the Add Component button, and select Audio Source from the Audio category.
Next, double-click the Gun script to edit it and add the following instance variable:
private AudioSource audioSource;
Add the following to Start()
:
audioSource = GetComponent<AudioSource>();
This just gets a reference to the attached AudioSource — you’ll be using this a lot. In fireBullet()
, add the following before the closing brace:
audioSource.PlayOneShot(SoundManager.Instance.gunFire);
This code plays the shooting sound. Note that there are two ways to play sound effects via code in Unity:
PlayOneShot()
, as you’ve used here, allows the same sound effect to play multiple times at once, effectively overlapping the sound. For example, the space marine could shoot one bullet and, while the sound effect for that was still playing, the space marine could quickly fire another bullet, and you’d hear both sound effects at once. The space marine fires quickly, so this is what we want, here.
Play()
only allows the sound effect to play a single time at once. If you play a sound effect, and then callPlay()
again, it will restart the sound effect, making the first effect sound like it was cut off. The advantage ofPlay()
overPlayOneShot()
is thatPlay()
can be stopped in progress whereasPlayOneShot()
cannot.
Save the file and go back to Unity. Play your game and fire that gun to hear the shooting sounds.
Playing alien death sounds
The game is sounding awesome, but it is a bit disappointing that you don’t hear the aliens die when you blast them away. So you will add the sound for that next.
Note that you can’t make the alien play its own sound as you did for the bullet, because when an alien dies, you destroy the Alien GameObject. When you destroy a GameObject, any sounds playing on an AudioSource stop instantly.
So, instead, you’ll make the GameManager play the death sounds. Although it’s tempting to use the SoundManager for all the sounds, doing so would narrow your options. You’ll learn more about this when you dive into the mixer.
public void PlayOneShot(AudioClip clip)
{
soundEffectAudio.PlayOneShot(clip);
}
This is a simple a wrapper call to PlayOneShot()
. Save and close the SoundManager script, then open the Alien script. In OnTriggerEnter()
, add the following before the closing brace:
SoundManager.Instance.PlayOneShot(SoundManager.Instance.alienDeath);
Save the script and head back to Unity. Play the game and obliterate some aliens. Explosions abound!
Adding a power-up
You’ve made it pretty difficult for the poor space marine. In Chapter 4, “Physics,” you added an excessive amount of aliens. In Chapter 5, “Pathfinding,” you’ve taught the aliens how to chase after the space marine, out for blood.
Worst of all, you’ve been making him work without theme music. Who does that? That’s cruel!
Now’s a good time to give our hero a boost — something to level the playing field. You’ll create a power-up that’ll sound really cool and temporarily triple the rate of fire.
First, you need to create the triple-shot gun. Open the Gun script, and add the following under the instance variables:
[SerializeField]
private bool isUpgraded;
[SerializeField]
private float upgradeTime = 10.0f;
private float currentTime;
isUpgraded
is a flag that lets the script know whether to fire one bullet or three.upgradeTime
is how long the upgrade will last (in seconds).currentTime
keeps track of how long it’s been since the gun was upgraded.
Take a look at fireBullet()
. Note how it creates each bullet on one line and sets its position on the following line. Instead of copying these lines multiple times, you’ll refactor it into a method.
Add the following method:
private Rigidbody createBullet()
{
GameObject bullet = Instantiate(bulletPrefab) as GameObject;
bullet.transform.position = launchPosition.position;
return bullet.GetComponent<Rigidbody>();
}
As you can see, this method simply encapsulates the bullet creation process. It returns a Rigidbody
after you create the bullet, all you need to do is set its velocity. Next, replace fireBullet()
with the following:
void fireBullet()
{
Rigidbody bullet = createBullet ();
bullet.velocity = transform.parent.forward * 100;
}
This code creates the bullet just like the previous version of the script. Now add the following to modify how the upgraded gun fires bullets, before the final curly brace:
if (isUpgraded)
{
Rigidbody bullet2 = createBullet();
bullet2.velocity = (transform.right + transform.forward / 0.5f) * 100;
Rigidbody bullet3 = createBullet();
bullet3.velocity = ((transform.right * -1) + transform.forward / 0.5f) * 100;
}
This bit of code fires the next two bullets at angles. It calculates the angle by adding the forward direction to either the right- or left-hand direction and dividing in half. Since there is no explicit left property, you multiply the value of right
by -1
to negate it.
Adding sound to the powerup
Now, to integrate the sound. Add the following before the closing brace:
if (isUpgraded)
{
audioSource.PlayOneShot(SoundManager.Instance.upgradedGunFire);
}
else
{
audioSource.PlayOneShot(SoundManager.Instance.gunFire);
}
This provides the shooting sound. Now you can see how working with SoundManager
makes playing sounds relatively easy. Next, you need a way to initiate the upgrade. Add the following new method:
public void UpgradeGun()
{
isUpgraded = true;
currentTime = 0;
}
This method lets the gun know it’s been upgraded and sets the counter timer to zero.
Save the file and switch back to Unity. Since you’re firing three bullets at once, there’s a chance that they’ll collide with each other, so you need to disable bullet collisions. Do you remember how to do this?
Click Edit ▸ Project Settings ▸ Physics and scroll down to the collision matrix. In the Bullet column, uncheck the Bullet row.

Believe it or not, you can test your power-up already, thanks to the power of live-editing values in the Unity editor.
Play the game and select the BobbleMarine-Body. In the Inspector, check the Is Upgraded checkbox and blast away!

Configuring the pickup
It’s great that you can test the power-up while debugging, but you need to add a way for the space marine to get his awesome new gun without cheating.
But first, you need to make it so that the power-up expires. After all, our hero will get spoiled if you leave it like this!
To do this, switch back to the Gun script and add the following to Update()
:
currentTime += Time.deltaTime;
if (currentTime > upgradeTime && isUpgraded == true)
{
isUpgraded = false;
}
This increments the time. If the time here is greater than the time the player has been upgraded, this code takes the upgrade away.
Excellent work! You’ve successfully coded the powerup and just need to add it to your game. Save the file and switch back to Unity.
In the Project window, open the Prefabs folder and select the Pickup prefab. You’ll see it has some configuration already. Click the Open button. You’ll see that the pickup is purple. That lets you know that it is using an outdated material.

In the Hierarchy, select the transp sphere child GameObject. You’ll see that it has a material attached to it. Change the shader to Universal Render Pipeline / Lit

Make sure the Workflow is set to Metallic and the Surface Type is set to Opaque. In the Surface Inputs, set the Base Map to #01C012, the Metallic Map to 0.894, and the Smoothness to 0.526. The shader will look like the following:

When completed, the upgrade should look as follows:

Now that’s an upgrade!
Writing the upgrade code
While still editing the Upgrade prefab, select the topmost GameObject. Click the Add Component button and select New Script. Name it Upgrade and click Create and Add. Open the script in your code editor. Replace the contents of the class with the following:
[SerializeField]
private Gun gun;
Then, add the following method:
void OnTriggerEnter(Collider other)
{
gun.UpgradeGun();
Destroy(gameObject);
SoundManager.Instance.PlayOneShot(SoundManager.Instance.powerUpPickup);
}
When the player collides with the power-up, this sets the gun to Upgrade mode, and then it will destroy itself (each pickup is good for one upgrade only). Also, a sound plays when the player picks up the upgrade.
Save and switch back to Unity.
Since the power-up should only be available to the space marine, you need to adjust the physics layers. Select the Pickup and in the Layer drop-down, set it to Upgrade. When prompted, select Yes, change children.
Now, you just need to adjust the collision matrix. Click Edit ▸ Project Settings ▸ Physics. In the layers matrix, uncheck the following from the Upgrade column: Bullet, Alien and Alien Head.

Configuring the game manager
With all that set up, you’re clear to write the spawning code for the power-up — yes, it spawns like the aliens. Close the Prefab in case you haven’t already. Open the GameManager script in your code editor and add the following instance variables:
[SerializeField]
private GameObject upgradePrefab;
[field: SerializeField]
public Gun gun { get;set;}
[SerializeField]
private float upgradeMaxTimeSpawn = 7.5f;
private bool spawnedUpgrade = false;
private float actualUpgradeTime = 0;
private float currentUpgradeTime = 0;
Here, you’ve defined several new variables:
upgradePrefab
refers to the GameObject the player must collide with to get the update — you already imported this into your project.gun
is a reference to Gun script because the gun needs to associate it with the upgrade.upgradeMaxTimeSpawn
is the maximum time that will pass before the upgrade spawns.spawnedUpgrade
tracks whether or not the upgrade has spawned since it can only spawn once.actualUpgradeTime
andcurrentUpgradeTime
track the current time until the upgrade spawns.
Now to determine the actual upgrade time. Add the following to Start()
:
actualUpgradeTime = Random.Range(upgradeMaxTimeSpawn - 3.0f, upgradeMaxTimeSpawn);
actualUpgradeTime = Mathf.Abs(actualUpgradeTime);
The upgrade time is a random number generated from Random.Range()
. The minimum value is the maximum value minus 3
, and Mathf.Abs
makes sure it’s a positive number.
Add the following to the start of Update()
:
currentUpgradeTime += Time.deltaTime;
This adds the amount of time from the past frame. Now, add the following:
if (currentUpgradeTime > actualUpgradeTime)
{
// 1
if (!spawnedUpgrade)
{
// 2
int randomNumber = Random.Range(0, spawnPoints.Length - 1);
GameObject spawnLocation = spawnPoints[randomNumber];
// 3
GameObject upgrade = Instantiate(upgradePrefab) as GameObject;
Upgrade upgradeScript = upgrade.GetComponent<Upgrade>();
upgradeScript.gun = gun;
upgrade.transform.position = spawnLocation.transform.position;
// 4
spawnedUpgrade = true;
}
}
Here’s the breakdown:
- After the random time period passes, this checks if the upgrade has already spawned.
- The upgrade will appear in one of the alien spawn points. This increases the risk-and-reward dynamic for the player because the sides of the arena are the most dangerous.
- This section handles the business of spawning the upgrade and associating the gun with it.
- This informs the code that an upgrade has been spawned.
Adding the upgrade sound
Now, back to the business of sound! The player needs an auditory cue when the power-up is available. Add the following after spawnedUpgrade = true
:
SoundManager.Instance.PlayOneShot(SoundManager.Instance.powerUpAppear);
Save the game and switch to Unity. Select the GameManager in the Hierarchy. In the Inspector, drag the Pickup from the Prefabs folder to the upgradePrefab field. Also, drag BobbleMarine-Body from the Hierarchy to Gun.

Since the SpaceMarine has a Gun script attached, Unity will reference the Gun component like it has done for Transforms and Rigidbodies.
Where to go from here
The game is really starting to take shape now. With a few lines of code and some sound files, it’s coming into its own thing. Hopefully, you are having with it.
Unfortunately, the sound levels are all over the place. The background music is sort of loud and the other sound effects are kind of a mess. Unity provides an audio mixer that allows you to tune all your sounds. You’ll put it to work in the next tutorial.
Discover more from Jezner Blog
Subscribe to get the latest posts sent to your email.