Day 5
User Interface
Today we’ll be working on the user interface. We need to setup a score counter and a game
over screen.
Score Counter
The plan is to have the GameMode object to keep score in the background of how many
hoops the player is able to clear. We also need to add that score zone we discussed earlier
to the HoopObstacle and signal the GameMode when the player goes through it.
Let’s start by adding another script to GameMode. Let’s call this one “GameRules”.
Here we first define an integer variable called score and initialize it to zero, because the
game starts with zero score.
Then, it is time to create another method. This one will be called IncreaseScore. You might
notice something interesting. I tagged this one as public. This keyword allows the method
to be called from outside this class. And since we want the obstacles to have the power to
tell the game when to increase the score, we want them to be able to use this method.
What we do inside the method isn’t super exciting yet. The first line uses the ++ operator
that increases the value of score variable by one. The second line prints the current score
in the console. The interesting part here is that we combine the text “Score: “ and the
variable score by just adding them together with a plus sign. As a result, the game should
print out something like “Score: 12”.
We don’t ever call this method so nothing gets printed yet. Let’s change that.
Go back to Unity. Then create another empty GameObject and place it inside the
HoopObstacle. Change its name to ScoreZone. Make sure
that everything is zeroed-out by locating a small gear icon
at the top-right corner of the Transform component and
clicking Reset inside it.
Next, we create a trigger by adding a Box Collider
2D component inside the ScoreZone object. Set
its size to X 0.5 and Y 4. You’ll notice that this
makes it fit snug inside the two rectangles. It is
also important that you check the Is Trigger
checkbox. Otherwise the player will just smash
its head against the invisible score zone.
Now we just need the script that will call the GameMode object when the trigger is hit. Add
a script component and call it ScoreUp.
Here we need to create a new Unity specific method called OnTriggerEnter2D. This method
gets called every time something enters the trigger on the object. In case you’re interested,
the Collider2D variable inside the parentheses is a parameter. Even though we never use it,
Unity requires that we have the variable there anyway. So, let’s just put it there.
You can probably guess what the line inside the method does. If you remember, we made
a script called GameRules for the GameMode and inside it made a method called
IncreaseScore. This line finds that script and calls the method inside.
Now, whenever something enters the score
zone, the score gets increased as a direct result.
Go to Unity and test it. Remember to open up
the Console tab so you can see the text getting
printed.
Seeing the score in the console isn’t very helpful for the end user, so let’s create a head-up
display that displays the score on the game screen.
Score Text
Create a Text object by going to GameObject menu and selecting UI and then Text. Rename
this to ScoreText and move it inside the Canvas object in the Hierarchy tab. Remember, you
can double-click the Canvas in the Hierarchy tab to focus on it in the Scene tab. This will
show you the whole Canvas on the screen. You can also use mouse wheel to zoom the
view in or out and second mouse button to grab and move the view.
Setting up a UI can be a bit work but it’s nothing difficult.
I want the text to be located at the top of the screen and smack in the middle. I also would
like the text to be white and large so that it’s easy to see.
First, let’s anchor the element top-center
and set the Pos X to 0. The Pos Y needs to
be negative because the text is going to
be located under the top of the screen. I
found -60 to work fine for me.
Second, the Text (Script) component needs some
work.
1.
Click the color and change it to white.
2.
Switch the Paragraph Alignment to Center.
3.
Replace the Text by “0” so that we don’t have to
initialize it in code.
4.
Change Font Style to Bold.
5.
Increase the Font Size to something around 48.
If you now find that the text in the Scene disappears,
you might need to increase the size of the text box
because the text can’t fit inside. Grab one of the blue
corners and drag it outwards until you can see the
text again.
Now we just have to hook up the UI Text into our IncreaseScore method.
Go back to the GameRules script. First and foremost, make a new Text variable at the top
of the class block to hold the ScoreText object.
This might prompt an error, because Text variables are part of Unity’s UI library. We’re
going to have to tell the script file to use that library by adding the last line here at the top
of the file.
After this, we have to initialize the variable. Let’s do it inside the Start method. And it’s not
just a matter of finding the ScoreText object in Unity. The ScoreText object has many
different components inside it. We’re interested in the Text (Script) component. So, we have
to specify that we want to get only that component.
Now that we have the Text component of the ScoreText object secured, we can go to the
IncreaseScore method. Instead of just printing the score in the console, let’s instead
change the text property (remember, the field that now has a “0” in it) of the Text
component.
This line does a couple of things. The variable scoreText points to the Text (Script)
component of the object. The .text after that points to the text property or the text field of
that component. We’re assigning the score variable to that field right after we increase it.
But what about the ToString()? Well, if you remember from yesterday, I explained that
variables can only hold data that is the same type as that variable. The score variable is an
integer. The text property is a character string. (Tip: If you hover your mouse over the text
property in Visual Studio, it will tell you its type.) They are incompatible. The ToString() is a
command that changes the integer into a string. This will make the two variables
compatible and we can assign one into the other.
If you now play the game, you can see the score increasing at the top of the screen as you
clear the hoops.
Game Over
Finally, let’s do something to stop the game once the player messes up and hits an
obstacle.
Make another Text Object and place it inside the Canvas object in the Hierarchy. Call it
GameOverText. Make it look all big and menacing and place it in the middle of the screen.
Don’t worry about it showing up prematurely. We’ll hide it in a script when the game starts.
Next, create a new script for the player. Let’s call this one PlayerCollision. Inside the script
create an OnCollisionEnter2D method.
And inside the method we’ll call an EndGame method inside GameRules script. But wait!
We don’t have an EndGame method there. That’s alright, we can create one later.
Go inside the GameRules script. We should do something about that Game Over text so
create a new variable called gameOverText and make its type GameObject.
Then, in the Start method, let’s grab the GameOverText game object, place it in the variable
we defined, and set its Active status as false. This will make it invisible in the scene.
Now, it’s time to get to that EndGame method. I want you to create it and make sure to set
it public so we can call it from the PlayerCollision script.
What’s happening inside it?
The first line grabs the PlayerCircle object from inside the game and destroys it. This makes
sure that the player can’t continue playing the game and hogging more points.
The second line sets the GameOverText active again.
Test it out. Now, if you hit an obstacle, you’ll get the game over message and the player
circle disappears.
That’s it for day 5! Congratulations for making it this far. Tomorrow we’ll start working on
the game art.
public class GameRules : MonoBehaviour {
int score = 0;
public void IncreaseScore () {
score++;
Debug.Log("Score: " + score);
}
...
public class ScoreUp : MonoBehaviour {
void OnTriggerEnter2D (Collider2D collisionInfo)
{
FindObjectOfType<GameRules>().IncreaseScore();
}
...
Text scoreText;
void Start () {
scoreText = GameObject.Find("ScoreText").GetComponent<Text>();
}
scoreText.text = score.ToString();
void OnCollisionEnter2D (Collision2D collisionInfo)
{
FindObjectOfType<GameRules>().EndGame();
}
public void EndGame () {
Destroy(GameObject.Find("PlayerCircle"));
gameOverText.SetActive(true);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
gameOverText = GameObject.Find("GameOverText");
gameOverText.SetActive(false);
If you have feedback or questions drop a note
on Twitter.