Journal 36 — Modify UI for Ammo and Add a Wave System in Unity

This article explains the modifications to add in UI changes to show the current ammo count compared to the total, and also the changes required to implement a wave system of enemies, and the corresponding UI changes to show the wave status.

  1. Ammo System

The ammo system update consists of a couple relatively simple changes to the UI and ammo pickup code. Essentially we need to track the total ammo compared to the current ammo, and pass these variables to the UI text. While updating, we can include a check to make sure the current ammo can only max out to the total ammo value.

We can start by adding in a total ammo variable to the Player C# script.

Unity C# script for Player, variables for tracking ammo

From there we can set the starting ammo and total ammo in the Start method. Then in the Update method, after firing a laser, we can subtract from the current ammo, and pass variables for the current and total ammo to the UIManager.

Unity C# script for Player, track ammo and update UI
Unity C# script for UIManager, update UI

The last item to update is when an ammo power up is picked up, we can limit the amount to stay below the total ammo.

Unity C# script for Player, check total ammo limit when ammo is picked up
Unity Playmode, ammo shows up in UI

The next update consists of a wave system, to account for a specific number of enemies to spawn per each wave. I have set this wave system example up to spawn three waves of enemies, and the player has to destroy all of the wave before the next wave shows up.

One of the biggest challenges I had was figuring out how to track globally the total enemies in the wave, when they are destroyed the enemy count updates, and when all the enemies are destroyed in a wave, the next wave starts. I did this via a combination of Singleton design patterns, and static variables across the GameManager, Player, and SpawnManager.

  1. Waves using Scriptable Objects

The wave system I am working with uses Scriptable Objects to store the specific number of enemies to spawn, so with this approach it is expandable to however many waves you would like. To start, you can create a C# script, and call it something like “Wave”, which includes a public List of gameobjects for the enemy sequence.

Unity C# script for Scriptable Object creation

Once the script is saved and compiles, you have a new menu option when right-clicking in your assets. You can now create a Scriptable Object and drag in the enemy prefabs to create your wave system.

Unity menu updated to create Scriptable Object
Unity Inspector and Assets, Scriptable Objects created for waves of enemies

2. Scriptable Object Spawn Manager

From a previous article, I prepared a SpawnManager to handle the spawning of a constant stream of enemies and also random powerups. For this exercise, I decided to break out the spawning of enemies into its own Spawner for Scriptable Objects. This script is also attached to the SpawnManager gameobject. The first part of the script includes a Singleton pattern to make the script accessible globally. I have also included a public list to hold all the wave Scriptable Objects created.

Unity C# script for Scriptable Object Spawn Manager
Unity Inspector for Scriptable Object Spawn Manager

The next part of the script includes a public static variable to assign the total enemy count at the start of a wave, and then this variable is subtracted from and tracked to start the next wave. In the Start method, I have a couple references to the SpawnManager and the UIManager.

Unity C# script for Scriptable Object Spawn Manager, public static variable and Start and Awake methods

The last part of the script consists of a coroutine to start the spawning. In the coroutine, we assign the wave of enemies and the total count, and pass this info to the UIManager. From there, we instantiate the wave of enemies.

Unity C# script for Scriptable Object Spawn Manager, spawn waves

3. Update Enemy Count

In the Enemy C# Script, we can update the enemy count whenever an enemy is destroyed, and also update the UI.

Unity C# script for Enemy, subtract the enemy count when destroyed

4. Update Spawn wave from GameManager

In the GameManager script which also has a Singleton pattern, we have created a property to get the current enemy count and if the current enemy count is 0, meaning the wave has been cleared, so we advance the current wave, and call the spawner coroutine.

Unity C# script for GameManager, enemy count property to update the next spawn wave

5. Update UI

For the UI updates, we need four things: text for the wave count, text for the number of enemies, text to indicate the wave is complete and the next wave is starting, and text to indicate all waves are destroyed.

In the UIManager, we can add several variables to reference.

Unity C# script for UIManager, spawn wave and enemy count variables

To update the enemy count, we can reference the enemy count from the GameManager Instance. The wave status is updated from the Scriptable Object spawner.

Unity C# script for UIManager, update wave and enemy info

As you see above, we want to show messages on screen on the wave status, whether the wave is complete and get ready for the next wave, or whether all waves have been destroyed. We can do this with a couple coroutines to set the screen text active and change the message.

Unity C# script for UIManager, update the wave text on screen to show next wave or all waves completed

In the Unity Hierarchy, we have our text gameobjects created in the canvas and dragged over to the Inspector.

Unity Hierarchy shows wave text gameobjects

Finally, here are the results of the wave system.

Unity Playmode, first wave active
Unity Playmode, first wave destroyed and message pops up
Unity Playmode, second wave starts, UI updates
Unity Playmode, second wave destroyed, and message pops up
Unity Playmode, third and final wave starts, UI updates
Unity Playmode, all waves destroyed, message pops up

Thank you for stopping by!

An Engineering Manager consultant who is seeking additional skills using Unity 3D for game and application development.