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.
- 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.
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.
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.
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.
- 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
In the Unity Hierarchy, we have our text gameobjects created in the canvas and dragged over to the Inspector.
Finally, here are the results of the wave system.
Thank you for stopping by!