Hi and welcome back to the Unity for Windows tutorial series. In this part we will add a GUI to our game (or you can follow these steps to add it to your own game) and then display the current score and save the highscore if you play well!
Resources
Downlod the starting project here (Part I): http://sdrv.ms/1dXRQBK
Download final project and assets from here: http://sdrv.ms/1dXRBqr
Open the project from Tutorial 1, or another project where you want to add the GUI.
1) Creating the GUI Game Object
a) First of all, we need to create a GameObject that will hold our GUI. Click GameObject->Create Empty
b) Now, click the new GameObject from the Hierachy and rename it to GUI:
c) Create another GameObject, but this time click Create Other –> GUI Texture:
d) A new GUI Texture GameObject is added to the Hierarchy:
e) Change the name of this to ScoreBackground and drag it in the GUI Game Object:
f) Cope the ScoreBG.png file from this tutorials assets folder to the games Textures folder
This texture will be used as the background for the players score, just to make it have some sort of container instead of just floating around in space.
g) Let’s position this by altering the properties of our new GUI Texture Game Object. Click it to see the properties:
First of all, we need to change the position of the GUI Texture. We do this by altering the Position Transform:
We set this to X:0 and Y:1.
This is because we want to have the texture in the upper-left corner of the screen.
This is how the coordinate system looks:
As we can see, setting the coordinates to 0,1 will put it in the upper-left corner of the screen. Think of the range between 0 and 1 as percentage. 1 is 100%. What we are saying is that the texture should be 0% from the left side of the screen and 100% from the bottom of the screen (in other words top)
If we press play, we can see the texture in the upper corner.. but right now, the center of our texture is placed at 0,1:
This doesnt look right. We want the upper left corner of our GUI Texture to be the center. If we change the values in the Pixel Inset property of the GUI Texture, we can change where the center of the texture should be.
If we change the X to 0 and the Y to –58 (height of the texture) we set the upper left corner of the texture to:
This is basically the same as 0,1 when we placed the position of the texture but now we operate with pixels instead of percent.
Press play now to see the GUI Texture at the correct position!
h) Next we need a font. First, inside the Textures folder, add a new folder called Fonts. Then add the Segoe UI font from your Windows folder to the project (it can be any True Type Font) by just drag it from the Windows Folder to the Textures folder of the project.
They should now be in the Fonts folder:
Delete all of them except the one named SEGOEUI my marking them and pressing Delete.
Now, click the SEGOEUI font:
And then click GameObject->Create Other->GUI Text
Drag the GUI Text Game Object inside the GUI Game Object:
Now, if you click it to view the properties, you can see that it got the font we highlighted when we created it.
If you press play, you can see the text in the center of the screen saying GUI Text.
We must now place this above the GUI Texture created earlier. Change the position of the GUI Text to this:
We place the text a few fixels from the left side of the screen and also a few pixels from the top of the screen.
We also set the Z to 0. This means that it should be rendered above the items at Z:0 like our GUI Texture. The Z is used to control the order of the items we want to render in the GUI.
Let’s also change the size of the font to 24:
Press play now to see our score container in action!
2) Setting the score and saving highscore
Next, we need to set the score of the player, and then when Game Over, check it against the high score. We also need to store the high score so we don’t loose it when we quit the game.
To do this, we got something called PlayerPrefs. It’s a way Unity can store simple data like integeres (numbers) and text.
a) In the GameController class, add a new GUIText variable called scoreText:
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour {
public GameObject enemy;
public GameObject laser;
public GUIText scoreText;
float spawnTimer;
float shootTimer;
// Use this for initialization
void Start () {
spawnTimer = 1.0f;
}
// Update is called once per frame
void Update () {
spawnTimer -= Time.deltaTime;
shootTimer -= Time.deltaTime;
if (spawnTimer <= 0.0f)
{
GameObject instance = (GameObject)Instantiate(enemy,
new Vector3(10,Random.Range(-4.0f,4.0f),-2.0f),
transform.rotation);
spawnTimer = 1.0f;
}
if (shootTimer <= 0.0f)
{
if (Input.GetButton(“Fire1”))
{
Vector3 spawnLaserPos = Camera.main.ScreenToWorldPoint(
new Vector3(-5.0f,
Input.mousePosition.y,
8));
Instantiate(laser, spawnLaserPos, Quaternion.identity);
shootTimer = 0.4f;
}
}
}
}
Now save the script and go to Unity, and click the Main Camera object to view the properties. You can see the GUI Text scoreText:
Now, drag the GUI Text Game Object we created inside the GUI Game Object to this property:
b) Next, we need to connect this filed with the players score. Go back to the GameController script and add a new line in the update function:
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour {
public GameObject enemy;
public GameObject laser;
public GUIText scoreText;
float spawnTimer;
float shootTimer;
// Use this for initialization
void Start () {
spawnTimer = 1.0f;
}
// Update is called once per frame
void Update () {
spawnTimer -= Time.deltaTime;
shootTimer -= Time.deltaTime;
scoreText.text = PlayerPrefs.GetInt(“CurrentScore”, 0).ToString();
if (spawnTimer <= 0.0f)
{
GameObject instance = (GameObject)Instantiate(enemy,
new Vector3(10,Random.Range(-4.0f,4.0f),-2.0f),
transform.rotation);
spawnTimer = 1.0f;
}
if (shootTimer <= 0.0f)
{
if (Input.GetButton(“Fire1”))
{
Vector3 spawnLaserPos = Camera.main.ScreenToWorldPoint(
new Vector3(-5.0f,
Input.mousePosition.y,
8));
Instantiate(laser, spawnLaserPos, Quaternion.identity);
shootTimer = 0.4f;
}
}
}
}
What we do here is to set the texture property of our GUI Text object. It can be whatever you want. We set it to the integer found in the PlayerPrefs called CurrentScore. It does not exist yet, so it will be set to 0 as thats the default value we have chosen for it.
PlayerPrefs.GetInt(“CurrentScore”, 0).ToString();
In other words, the code does this. Find the integer CurrentScore from Player prefs. If it doesnt exist, set it to 0.
c) Now, we must give the player some score when he/she manages to shoot down a spaceship!
In the enemy script EnemyController.cs, let’s add a function that gives the player some score, and then call the script when an enemy dies:
using UnityEngine;
using System.Collections;
public class EnemyController : MonoBehaviour {
public float speed;
public GameObject explosion;
// Use this for initialization
void Start () {
}
void AddScore()
{
int _tempScore = PlayerPrefs.GetInt(“CurrentScore”);
_tempScore += 10;
PlayerPrefs.SetInt(“CurrentScore”, _tempScore);
}
void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag.Equals(“Laser”))
{
Destroy(other.gameObject);
Destroy(this.gameObject);
Instantiate(explosion, this.transform.position, this.transform.rotation);
AddScore();
}
}
// Update is called once per frame
void Update () {
this.transform.position -= new Vector3(speed, 0, 0) * Time.deltaTime;
if (this.transform.position.x <= -10.0f)
{
GameOver();
}
}
void GameOver()
{
Application.LoadLevel(1);
}
}
What we do here is to get the score stored in PlayerScore, add 10 to it, and then store it back. There are MANY ways to do this, like using a singelton or a static integer, but just to show you the PlayerPrefs class, I decided to go this way.
The problem with this score right now is that it will not be reset if you quit the game or when you start a new game after game over. In the GameController script, we must set this to 0 when we start the game. Let’s do this now. Open the GameController script and make the following changes:
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour {
public GameObject enemy;
public GameObject laser;
public GUIText scoreText;
float spawnTimer;
float shootTimer;
// Use this for initialization
void Start () {
spawnTimer = 1.0f;
PlayerPrefs.SetInt(“CurrentScore”, 0);
}
// Update is called once per frame
void Update () {
spawnTimer -= Time.deltaTime;
shootTimer -= Time.deltaTime;
scoreText.text = PlayerPrefs.GetInt(“CurrentScore”, 0).ToString();
if (spawnTimer <= 0.0f)
{
GameObject instance = (GameObject)Instantiate(enemy,
new Vector3(10,Random.Range(-4.0f,4.0f),-2.0f),
transform.rotation);
spawnTimer = 1.0f;
}
if (shootTimer <= 0.0f)
{
if (Input.GetButton(“Fire1”))
{
Vector3 spawnLaserPos = Camera.main.ScreenToWorldPoint(
new Vector3(-5.0f,
Input.mousePosition.y,
8));
Instantiate(laser, spawnLaserPos, Quaternion.identity);
shootTimer = 0.4f;
}
}
}
}
This sets the CurrentScore to 0 when a new game is started (the Start() function will run only once when the GameController script is executed for the first time).
3) What about the highscore?
a) In the gameOver scene, we want to display the highscore. First of all, we need to check if the player got a highscore, and if yes, save it. Open the GameOverController script and make these changes:
using UnityEngine;
using System.Collections;
public class GameOverController : MonoBehaviour {
float gameOverTimer;
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt(“CurrentScore”, 0);
int _highscore = PlayerPrefs.GetInt(“HighScore”, 0);
if (_score > _highscore)
PlayerPrefs.SetInt(“HighScore”, _score);
}
// Use this for initialization
void Start () {
gameOverTimer = 5.0f;
CheckHighscore();
}
// Update is called once per frame
void Update () {
gameOverTimer -= Time.deltaTime;
if(gameOverTimer <= 0.0f)
Application.LoadLevel(0);
}
}
Nothing should be new here. We get the score and the highscore and check if we got a score better than the highscore. if yes, store them.
b) Now, it would be nice to see the highscore and what score the player got. Create another Game Object in the Game Over scene and name it GUI, and select the SEGOEUI font:
Create a new GUI Text like we did before and name this ScoreText. Do the same step to create another GUI Text named HighScoreText.
You should now have two GUI Text objects:
c) Set the transform of the GUI Game Object to X:0, Y:0 and Z:0
d) Set the transform of the ScoreText to this:
e) Set the tranform of the HighScoreText to this:
Your result should be something like this:
f) Let’s set these in the script:
using UnityEngine;
using System.Collections;
public class GameOverController : MonoBehaviour {
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt(“CurrentScore”, 0);
int _highscore = PlayerPrefs.GetInt(“HighScore”, 0);
if (_score > _highscore)
PlayerPrefs.SetInt(“HighScore”, _score);
}
// Use this for initialization
void Start () {
gameOverTimer = 5.0f;
CheckHighscore();
scoreText.text = “Score: ” + PlayerPrefs.GetInt(“CurrentScore”, 0);
highScoreText.text = “Highscore: ” + PlayerPrefs.GetInt(“HighScore”, 0);
}
// Update is called once per frame
void Update () {
gameOverTimer -= Time.deltaTime;
if(gameOverTimer <= 0.0f)
Application.LoadLevel(0);
}
}
What happens here is that we create two new public containers for our GUI Text objects, and then we set these to the values we find in the PlayerPrefs world.
Now, in Unity, drag the two GUI Text objects to the correct containers in the property view of Main Camera:
Go back to the gameScene and press play. Play the game for a while (it’s currently very easy) and die. You should now see the score system working well!
Final words
In this tutorial we have created one component of the UI. This component is set relative to the screen. When designing UI for devices with variable resolutions it’s very important to keep in mind that you want the have a flexible UI. By creating a UI of many objects that are placed say 10% from the left side of the screen and so on, the UI adapts to different resolutions.
Many are creating a picture that is having the resolution of the screen and then just scales this based on the games resolution. This will mostly be ugly on different devices and is hard to work with.
The UI in this game will look about the same on all devices like mobiles, tablets and computers.
Download final project and assets from here: http://sdrv.ms/1dXRBqr
Pingback: Unity for Windows V–Connecting To The Cloud with Windows Azure Mobile Services | digitalerr0r