Adding a Canvas and an EventSystem
Start a new project called UI & Data Persistence. As with all the projects so far, be sure to select the 2D option.
Right-click in the Hierarchy window and select UI | Canvas. Before a project can have any UI objects it must first have a Canvas object. In the future, you can save time by adding any UI object and if you don’t have a Canvas object then Unity adds one automatically. I thought that explicitly adding it would make it clear what we are doing. Any UI objects we add, need to be a child of this Canvas. We will see this in a minute.
Notice that two objects have been added to the project, a Canvas, and an EventSystem. You can’t have one without the other. The EventSystem object is what alerts our UI objects when something happens to them. The number of events we can respond to is extremely wide and varied. In this tutorial, we will only be interested in the click of a button.
Configuring the Canvas
Make sure that Canvas is selected in the Hierarchy window. Find the Render Mode option in the Inspector window and change it to Screen-space camera. Next, drag Main camera from the Hierarchy window over to the Render Camera field. What we have just done is to set the view of the game camera, Main Camera, as the extent of our UI canvas. We can now add UI anywhere on the visible area of the player’s screen.
Adding a Button and Text objects
Right-click the Canvas object in the Hierarchy window and select UI | Button. A new button has been added as a child of the Canvas object. Also, notice that it automatically has a Text child object. Select the Text object by left-clicking it once and change the Text property in the Inspector window to Add one.
Now we can add a Text object. Right-click the Canvas object and select UI | Text. Right-click the new Text object and choose Rename, and change its name to score.
Change its Text property to Score, its Font Size to 25, and its Color to white(or similar easily seen color) by editing in the appropriate place in the Inspector window. This next image shows how and where to do these things.
Next, we need another new Text object. Create one as we just did and change its name to hiscore, its Text property to Hi Score, its Font Size to 25, and its Color to white(or similar).
Arrange your screen to look roughly like mine. You can select “move mode” by pressing W and then you can move each object individually, using the horizontal and vertical arrows. If you have trouble selecting the objects individually in the Scene window then select them one at a time from the Hierarchy window.
Now we are ready to make our UI actually do something.
Writing the C# code
As we have done in previous projects we want to add an empty GameController object with a GameController C# script component. To achieve this, right-click in the Hierarchy window and select Create Empty…. Rename the new game object to GameController. Now click the Add Component button in the Inspector window, choose Script | New Script and name it GameController, then click Create and Add. Open the script to edit it and change the code to look exactly like this next code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
using UnityEngine; using UnityEngine.UI; using System.Collections; public class GameController : MonoBehaviour { public Text scoreText; public Text hiscoreText; // the variables int score = 0; int hiscore; // Use this for initialization void Start () { hiscore = PlayerPrefs.GetInt ("hiscore", 0); scoreText.text = "Score:" + score; hiscoreText.text = "HiScore:" + hiscore; } // Update is called once per frame void Update () { } public void incrementScore(){ // Add to the score score++; // Update the score text scoreText.text = "Score:" + score; // Is there a new hiscore? if (score > hiscore) { // Set the new hiscore hiscore = score; // Save the new hiscore PlayerPrefs.SetInt ("hiscore", hiscore); // Update the hiscore text hiscoreText.text = "Hiscore:" + hiscore; } } } |
Explaining the code
Let’s do this in chunks. Near the top of the code block, we have this code.
1 2 3 4 5 6 7 |
// Two text objects public Text scoreText; public Text hiscoreText; // the variables int score = 0; int hiscore; |
The first thing to notice is that we have two objects of the type Text, scoreText and hiscoreText. It is important to know that to use objects of this type Text we needed to make them available. We did so with the second line of code we typed, using UnityEngine.UI. Next, we declare two regular int variables, score and hiscore. Here is what will happen in this project. The score and hiscore variables, as their names make plain, will be used to keep track of the score and highest score of the player. The scoreText and hiscoreText objects will be associated with the UI Text objects we have added and will be used to display the values stored in score and hiscore. Simple-ish.
Next, we coded the Start method, here it is again. Remember from previous projects that this method executes when the object first comes into use in the game. So, in this case, it will execute as soon as the game starts.
1 2 3 4 5 6 7 |
// Use this for initialization void Start () { hiscore = PlayerPrefs.GetInt ("hiscore", 0); scoreText.text = "Score:" + score; hiscoreText.text = "HiScore:" + hiscore; } |
Here is how this method works. The first line uses the PlayerPrefs class’ GetInt method to initialize the hiscore variable with a value, labeled as "hiscore" stored in a file associated with this game. The file is provided automatically, we don’t need to do anything to get it. If no value with the label "hiscore" exists, then the value zero is used. The first time we run the game the label "hiscore" and the associated value will not exist. Therefore the value of hiscore is zero.
Next, the code sets the text property of scoreText by concatenating the string "Score:" with whatever value is currently held in score. This, of course, is zero because that is what we initialized it to. Next, hiscoreText gets the same treatment. If, however, PlayerPrefs.GetInt had successfully initialized hiscore with a value, at this point, it would be stored as the text value in hiscoreText.
The main part of the code we just wrote is the incrementScore method. Also, notice that nowhere in our code do we actually call this method. We will fix this soon. For now, let’s look at what the code does when it is eventually called.
1 2 3 4 5 |
// Add to the score score++; // Update the score text scoreText.text = "Score:" + score;<br> |
The first part, re-shown above, increments (adds one) to score then updates scoreText.text, using the new value of score, in exactly the same way that we initialized it in the Start method.
The last of the code in the incrementScore method is wrapped in a if statement that only executes when score is greater than hiscore. In other words, the code below will execute each time a new high score is achieved by the player.
1 2 3 4 5 6 7 8 9 10 11 12 |
// Is there a new hiscore? if (score > hiscore) { // Set the new hiscore hiscore = score; // Save the new hiscore PlayerPrefs.SetInt ("hiscore", hiscore); // Update the hiscore text hiscoreText.text = "Hiscore:" + hiscore; } |
Inside the if block hiscore is set to score, the new player high score. The next line of code uses PlayerPrefs.SetInt to write the value contained in hiscore into the file provided by Unity and label it as "hiscore". Note that if the "hiscore" the label does not exist, Unity creates it. This means that not only has the players new achievement just been saved, but also, the next time the game is run it will be loaded and displayed because of the code we wrote in the Start method. The final line of code uses the exact same code as we saw in the Start method to set the text property of the hiscoreText object.
Now our code is preparing the Text objects and score-related variables, incrementing, checking for new player high scores, and updating the appropriate Text objects. We just need to associate the Text objects in our UI with the Text objects in our script and work out how to call the incrementScore method when the player clicks the button in the UI.
Updating the UI Text and calling the incrementScore method
Back in Unity, select the GameController object in the Hierarchy window. Notice the two new fields on the Game Controller (Script) component. These are our two public Text objects.
- Drag the score object from the Hierarchy window and drop it on the Score Text field of the script component in the Inspector window.
- Drag the hiscore object from the Hierarchy window and drop it on the Hiscore Text field.
It should look like this when you are done.
Now, to make the whole thing work, we need to make the button call the incrementScore method in the GameController object. I love how easily Unity makes this.
Select the button object in the Hierarchy window by single left-clicking it. Next, click the + button in Inspector window as shown next.
Now Drag the GameController object from the Hierarchy window to the (None) Object field we just added to the OnClick() event, highlighted for clarity next.
Select the GameController | incrementScore() method from the no function drop-down.
Here is what that part of the screen should look like now.
Run the game and click the Add One button. Notice that the score increases and as the hiscore was zero it increases along with the score. Don’t click too many times. Quit the game by clicking the same button you used to start the game. Now start the game again and notice that the hiscore remains.
Now start clicking again. Notice that the hiscore will begin to increase once the score exceeds it. Quit and restart as many times as you like, even quit and restart Unity itself, to demonstrate that the hiscore is being saved to a file, as intended.
I know I keep saying it but we are getting really close to building a real game.
I’m having trouble: the GameController object doesn’t have any text attached to it, even after typing ‘Public Text …’ in code (and I am using UnityEngine.UI).
Solved