You may not realize it when you first start looking into making your own game, but Unity doesn’t know anything about lives, scores or any of the other game elements that we all took for granted before this point.
Before we can even think about display such things, we have to code in the basic information of these elements. In their simplest form, they are variables that we add to or subtract from as certain events occur in our game. Let’s review…
Here we set up the code so that the Player script now has a reference to both the number of Lives and the Score. We put these on the Player script because the Player will be the one to modify them but either being hit by or shooting down Enemies.
But in order for them to be displayed, the UI need to know about them too. This is why we create a UI Manager class to handle such information without having to hold onto it.
To display both the Score and the Lives, we will use these three Variables. TMP_Text was covered previously in our article about TextMeshPro. Sprite and Image are both part of the Unity UI system. This means that we will need to have our UIManager using both the UnityEngine.UI and TMPro namespaces. If you get any errors when setting up these variables check that both namespaces are stated at the top of the script.
For the score, we need to set up a TMP Text field on our games Canvas. When you are setting it up, you can place in a ‘dummy’ score so that you can get the placement and font to your liking, we will be overwriting that at the start of the game.
Here you see that we are using the extension .text to _scoreText in order to change the displayed text to “Score: 0”. You may also note that, I could have put the whole string in quotes instead of appending 0 to the end of the string. But I did in the fashion above to have uniform look with other instances of modifying the _scoreText. This is simply a personal preference.
Now since we are using an event system in this game, there are a few things to take care of.
First we need a handle on the Player in order to get access to because we want to access more than it’s Static Events. And we grab the reference in OnEnable() instead of using a serialized field because the Player can be destroyed and leave the reference Null later. The Find() function is expensive in optimization but will be fine here as it is only called once and only at the start or restart of the scene. Next we subscribe the UIManager to the OnEnemyDeath and OnPlayerDamaged events by assigning EnemyDeath and PlayerDamaged respectively.
Both events have parameters that are passed along when the event is called and both assigned Methods need to be able to accept the parameter. But, unlike PlayerDamaged, EnemyDeath in UIManager does not use the parameter that it is passed (the enemy score value in this case) so we name the parameter notUsed for any coders that come after us.
Both of the methods also start a Coroutine because it would seem that IEnumerators can’t be triggered directly by events. Let’s take a look at what they do next.
Here I have each Update coroutine waiting for the end of the frame to do anything. I’ve done this to allow Player script to work through it’s event calls before the UIManager tries to updates. This allows any extra point tallies to roll in during the frame and makes sure that all those points are counted before the Score is updated. This can also be accomplished by changing the priority of the Player script in Unity’s Execution Order, but this may lead to unintended effects.
Now let’s address the Lives Display. Since we are using an Image instead of Text counter, we need to store multiple versions of the Image in Sprite form. For this project, we are using four variants of the same sprite with each modified to so how many lives are left from zero to three.
With each of the sprites loaded into the Array _livesSprites, we can easily pass in the Lives parameter from the event to set the right sprite to the _livesDisplay.
And now with a few handfuls of lines of code, our game knows about Lives and Score as well as display them properly for the User. Next we will look at what happens when the User has run out of Lives.