Posted on

How to make Pong in Unity Lesson 3

Play Classic Pong

Now we want to create a prefab for the ball object of Pong, which is the other major piece of the game besides the paddle. To do this we will begin with the ball controller script. Go ahead and create a new C# script in your scripts folder and call it BallController. Then double click on it to open it up in your coding environment.

The first thing we will do inside this script is to create some new variables.

Rigidbody2D myRb;
bool setSpeed;
[SerializeField] float speedUp;
float xSpeed;
float ySpeed;

Now, we need to initialize our Rigidbody2D variable and we can do this within the Start function. Next, let us create a new function that we will use to move the ball. This will be a void function called MoveBall with no

Developer’s Insight: We need to think about how we want to move the ball. We are already moving the paddles with the Translate function and if we move the ball in the same way then there will be no physics interactions that we need in order to trigger different events. Because of this, it would be best to move the ball using the velocity variable of the Rigidbody component.

using Photon.Chat;
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PhotonChatManager : MonoBehaviour, IChatClientListener
{
    #region Setup

    [SerializeField] GameObject joinChatButton;
    ChatClient chatClient;
    bool isConnected;
    [SerializeField] string username;

    public void UsernameOnValueChange(string valueIn)
    {
        username = valueIn;
    }

    public void ChatConnectOnClick()
    {
        isConnected = true;
        chatClient = new ChatClient(this);
        //chatClient.ChatRegion = "US";
        chatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new AuthenticationValues(username));
        Debug.Log("Connenting");
    }

    #endregion Setup

    #region General

    [SerializeField] GameObject chatPanel;
    string privateReceiver = "";
    string currentChat;
    [SerializeField] InputField chatField;
    [SerializeField] Text chatDisplay;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (isConnected)
        {
            chatClient.Service();
        }

        if (chatField.text != "" && Input.GetKey(KeyCode.Return))
        {
            SubmitPublicChatOnClick();
            SubmitPrivateChatOnClick();
        }
    }

    #endregion General

    #region PublicChat

    public void SubmitPublicChatOnClick()
    {
        if (privateReceiver == "")
        {
            chatClient.PublishMessage("RegionChannel", currentChat);
            chatField.text = "";
            currentChat = "";
        }
    }

    public void TypeChatOnValueChange(string valueIn)
    {
        currentChat = valueIn;
    }

    #endregion PublicChat

    #region PrivateChat

    public void ReceiverOnValueChange(string valueIn)
    {
        privateReceiver = valueIn;
    }

    public void SubmitPrivateChatOnClick()
    {
        if (privateReceiver != "")
        {
            chatClient.SendPrivateMessage(privateReceiver, currentChat);
            chatField.text = "";
            currentChat = "";
        }
    }

    #endregion PrivateChat

    #region Callbacks

    public void DebugReturn(DebugLevel level, string message)
    {
        //throw new System.NotImplementedException();
    }

    public void OnChatStateChange(ChatState state)
    {
        if(state == ChatState.Uninitialized)
        {
            isConnected = false;
            joinChatButton.SetActive(true);
            chatPanel.SetActive(false);
        }
    }

    public void OnConnected()
    {
        Debug.Log("Connected");
        joinChatButton.SetActive(false);
        chatClient.Subscribe(new string[] { "RegionChannel" });
    }

    public void OnDisconnected()
    {
        isConnected = false;
        joinChatButton.SetActive(true);
        chatPanel.SetActive(false);
    }

    public void OnGetMessages(string channelName, string[] senders, object[] messages)
    {
        string msgs = "";
        for (int i = 0; i < senders.Length; i++)
        {
            msgs = string.Format("{0}: {1}", senders[i], messages[i]);

            chatDisplay.text += "\n" + msgs;

            Debug.Log(msgs);
        }

    }

    public void OnPrivateMessage(string sender, object message, string channelName)
    {
        string msgs = "";

        msgs = string.Format("(Private) {0}: {1}", sender, message);

        chatDisplay.text += "\n " + msgs;

        Debug.Log(msgs);
        
    }

    public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
    {
        throw new System.NotImplementedException();
    }

    public void OnSubscribed(string[] channels, bool[] results)
    {
        chatPanel.SetActive(true);
    }

    public void OnUnsubscribed(string[] channels)
    {
        throw new System.NotImplementedException();
    }

    public void OnUserSubscribed(string channel, string user)
    {
        throw new System.NotImplementedException();
    }

    public void OnUserUnsubscribed(string channel, string user)
    {
        throw new System.NotImplementedException();
    }

    #endregion Callbacks
}

Inside this function, we want to set the velocity the balls Rigidbody using a new Vector2 value of our xSpeed and ySpeed variables. We then want to call this function with our Update function.

But before we call the MoveBall function in the Update function we need to add some code to set the speed of the ball. This can be done by first, checking to see if the setSpeed variable equals false. If it is we then want to set it to true and set the xSpeed and ySpeed variables equal to a random range between the same number negative and positive.

Now we need to code for the different physics interactions our ball can have. The first will be for when it collides with another 2D collider. This is done by adding the special OnCollisionEnter2D function. Inside this function, we need to first hand the condition for if our ball collides with a wall object. Inside this condition, we must simple inverse the value of our xSpeed variable by multiplying it by -1. We then need to handle the condition for if our ball collides with a paddle. Inside this, if statement we must first invert the ySpeed variable by doing the same as we did with the xSpeed variable above. Then depending on the direction of the ball, we need to add or subtract the speedUp value to the ySpeed and xSpeed variables. If the speed is positive then you want to add. If the speed is negative then subtract.

Here is our version of this script so far.

using UnityEngine;
using System.Collections;

public class BallController : MonoBehaviour {

    Rigidbody2D myRb;
    bool setSpeed;
	[SerializeField] float speedUp;
	float xSpeed;
	float ySpeed;

	void Start()
	{
		myRb = GetComponent<Rigidbody2D>();
	}
	
	void Update () {
		
            if(!setSpeed)
            {
                setSpeed = true;
                
                xSpeed = Random.Range(1f, 2f) * Random.Range(0, 2) * 2 - 1;
                ySpeed = Random.Range(1f, 2f) * Random.Range(0, 2) * 2 - 1;
            }
			MoveBall();
		
	}

    void MoveBall()
    {
        myRb.velocity = new Vector2(xSpeed, ySpeed);
    }

	void OnCollisionEnter2D(Collision2D other)
	{
		
		if(other.transform.tag =="Wall")
		{
			xSpeed = xSpeed*-1;
		}
		
        if (other.transform.tag == "Paddle" )
        {
            ySpeed = ySpeed * -1;

            if(ySpeed > 0)
            {
                ySpeed += speedUp;
            }
            else
            {
                ySpeed -= speedUp;
            }
            if (xSpeed > 0)
            {
                xSpeed += speedUp;
            }
            else
            {
                xSpeed -= speedUp;
            }
        }

	}
}
using Photon.Chat;
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PhotonChatManager : MonoBehaviour, IChatClientListener
{
    #region Setup

    [SerializeField] GameObject joinChatButton;
    ChatClient chatClient;
    bool isConnected;
    [SerializeField] string username;

    public void UsernameOnValueChange(string valueIn)
    {
        username = valueIn;
    }

    public void ChatConnectOnClick()
    {
        isConnected = true;
        chatClient = new ChatClient(this);
        //chatClient.ChatRegion = "US";
        chatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new AuthenticationValues(username));
        Debug.Log("Connenting");
    }

    #endregion Setup

    #region General

    [SerializeField] GameObject chatPanel;
    string privateReceiver = "";
    string currentChat;
    [SerializeField] InputField chatField;
    [SerializeField] Text chatDisplay;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (isConnected)
        {
            chatClient.Service();
        }

        if (chatField.text != "" &amp;&amp; Input.GetKey(KeyCode.Return))
        {
            SubmitPublicChatOnClick();
            SubmitPrivateChatOnClick();
        }
    }

    #endregion General

    #region PublicChat

    public void SubmitPublicChatOnClick()
    {
        if (privateReceiver == "")
        {
            chatClient.PublishMessage("RegionChannel", currentChat);
            chatField.text = "";
            currentChat = "";
        }
    }

    public void TypeChatOnValueChange(string valueIn)
    {
        currentChat = valueIn;
    }

    #endregion PublicChat

    #region PrivateChat

    public void ReceiverOnValueChange(string valueIn)
    {
        privateReceiver = valueIn;
    }

    public void SubmitPrivateChatOnClick()
    {
        if (privateReceiver != "")
        {
            chatClient.SendPrivateMessage(privateReceiver, currentChat);
            chatField.text = "";
            currentChat = "";
        }
    }

    #endregion PrivateChat

    #region Callbacks

    public void DebugReturn(DebugLevel level, string message)
    {
        //throw new System.NotImplementedException();
    }

    public void OnChatStateChange(ChatState state)
    {
        if(state == ChatState.Uninitialized)
        {
            isConnected = false;
            joinChatButton.SetActive(true);
            chatPanel.SetActive(false);
        }
    }

    public void OnConnected()
    {
        Debug.Log("Connected");
        joinChatButton.SetActive(false);
        chatClient.Subscribe(new string[] { "RegionChannel" });
    }

    public void OnDisconnected()
    {
        isConnected = false;
        joinChatButton.SetActive(true);
        chatPanel.SetActive(false);
    }

    public void OnGetMessages(string channelName, string[] senders, object[] messages)
    {
        string msgs = "";
        for (int i = 0; i &lt; senders.Length; i++)
        {
            msgs = string.Format("{0}: {1}", senders[i], messages[i]);

            chatDisplay.text += "\n" + msgs;

            Debug.Log(msgs);
        }

    }

    public void OnPrivateMessage(string sender, object message, string channelName)
    {
        string msgs = "";

        msgs = string.Format("(Private) {0}: {1}", sender, message);

        chatDisplay.text += "\n " + msgs;

        Debug.Log(msgs);
        
    }

    public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
    {
        throw new System.NotImplementedException();
    }

    public void OnSubscribed(string[] channels, bool[] results)
    {
        chatPanel.SetActive(true);
    }

    public void OnUnsubscribed(string[] channels)
    {
        throw new System.NotImplementedException();
    }

    public void OnUserSubscribed(string channel, string user)
    {
        throw new System.NotImplementedException();
    }

    public void OnUserUnsubscribed(string channel, string user)
    {
        throw new System.NotImplementedException();
    }

    #endregion Callbacks
}

There is another physics interaction that we will need to code for the ball but we first need to code a different script so for now we will save this script and revisit it later. Go ahead and return to Unity. Inside Unity Create the following object.

  • : This is a 2D sprite object with the ball image as the sprite. It also has a Circle Collider 2D component, a Rigidbody 2D and our BallController script.

Once you have created this object in your scene, go ahead and turn it into a prefab by dragging it from your hierarchy into your Prefabs folder. Now with the ball and paddles still in your scene, you can test your game by clicking the play button. The ball should start moving immediately and If it hits the walls or you paddles it should “bounce” off.

Creative Thought: You could find a way to spawn more balls into your game making it harder for the players to protect their endzone.

Posted on

How to make Pong In Unity Lesson 2

Play Classic Pong

In Pong, each player controls his own paddle. The basic Pong game only allows players to move in two directions on the same axis in order to guard their endzone. 

Creative thought: if you wanted to you could allow players to move their paddle in four directions within a boundary zone.

To create the paddle we will start by coding the player controls. First, create a new folder in the project window and call it Scripts. Then create a new C# script and call it PlayerController. Once created double click on it to open it up in your default coding environment.

Once opened, we need to create some new variables.

public string leftKey, rightKey;
public float speed;

Next, we can create a new function for the paddle movement. This will be a void function and you can call it PaddleMovement. There will be no parameters for this function.

Developer’s Insight: Here I want to take some time to talk about what different ways we could go about moving the player’s paddle. First, we will need to check for the player’s input. There are several different input options that we could look for.  If we were building a mobile game we could use touch input or UI buttons. If we were making it for consoles we could read an axis for a thumbstick control but for the sake of this tutorial and to keep things simple we are just going to read in some keyboard keys which is why we have the two string variables.

As for moving the paddles, there are several different methods we could use all of which would be just fine though some may be better than others for this specific game we are creating. we could use the velocity of a Rigidbody. Or we could use a character controller component and the Move function. We could have the paddle lerp to a specific location. This would work well with a finger touch input or mouse click. However, what will work best for our game will be the Translate function.

using Photon.Chat;
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PhotonChatManager : MonoBehaviour, IChatClientListener
{
    #region Setup

    [SerializeField] GameObject joinChatButton;
    ChatClient chatClient;
    bool isConnected;
    [SerializeField] string username;

    public void UsernameOnValueChange(string valueIn)
    {
        username = valueIn;
    }

    public void ChatConnectOnClick()
    {
        isConnected = true;
        chatClient = new ChatClient(this);
        //chatClient.ChatRegion = "US";
        chatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new AuthenticationValues(username));
        Debug.Log("Connenting");
    }

    #endregion Setup

    #region General

    [SerializeField] GameObject chatPanel;
    string privateReceiver = "";
    string currentChat;
    [SerializeField] InputField chatField;
    [SerializeField] Text chatDisplay;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (isConnected)
        {
            chatClient.Service();
        }

        if (chatField.text != "" &amp;&amp; Input.GetKey(KeyCode.Return))
        {
            SubmitPublicChatOnClick();
            SubmitPrivateChatOnClick();
        }
    }

    #endregion General

    #region PublicChat

    public void SubmitPublicChatOnClick()
    {
        if (privateReceiver == "")
        {
            chatClient.PublishMessage("RegionChannel", currentChat);
            chatField.text = "";
            currentChat = "";
        }
    }

    public void TypeChatOnValueChange(string valueIn)
    {
        currentChat = valueIn;
    }

    #endregion PublicChat

    #region PrivateChat

    public void ReceiverOnValueChange(string valueIn)
    {
        privateReceiver = valueIn;
    }

    public void SubmitPrivateChatOnClick()
    {
        if (privateReceiver != "")
        {
            chatClient.SendPrivateMessage(privateReceiver, currentChat);
            chatField.text = "";
            currentChat = "";
        }
    }

    #endregion PrivateChat

    #region Callbacks

    public void DebugReturn(DebugLevel level, string message)
    {
        //throw new System.NotImplementedException();
    }

    public void OnChatStateChange(ChatState state)
    {
        if(state == ChatState.Uninitialized)
        {
            isConnected = false;
            joinChatButton.SetActive(true);
            chatPanel.SetActive(false);
        }
    }

    public void OnConnected()
    {
        Debug.Log("Connected");
        joinChatButton.SetActive(false);
        chatClient.Subscribe(new string[] { "RegionChannel" });
    }

    public void OnDisconnected()
    {
        isConnected = false;
        joinChatButton.SetActive(true);
        chatPanel.SetActive(false);
    }

    public void OnGetMessages(string channelName, string[] senders, object[] messages)
    {
        string msgs = "";
        for (int i = 0; i &lt; senders.Length; i++)
        {
            msgs = string.Format("{0}: {1}", senders[i], messages[i]);

            chatDisplay.text += "\n" + msgs;

            Debug.Log(msgs);
        }

    }

    public void OnPrivateMessage(string sender, object message, string channelName)
    {
        string msgs = "";

        msgs = string.Format("(Private) {0}: {1}", sender, message);

        chatDisplay.text += "\n " + msgs;

        Debug.Log(msgs);
        
    }

    public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
    {
        throw new System.NotImplementedException();
    }

    public void OnSubscribed(string[] channels, bool[] results)
    {
        chatPanel.SetActive(true);
    }

    public void OnUnsubscribed(string[] channels)
    {
        throw new System.NotImplementedException();
    }

    public void OnUserSubscribed(string channel, string user)
    {
        throw new System.NotImplementedException();
    }

    public void OnUserUnsubscribed(string channel, string user)
    {
        throw new System.NotImplementedException();
    }

    #endregion Callbacks
}

Inside your PaddleMovement function, first, check if the player is pressing a keyboard key by using the leftKey variable. Then inside this, if statement, use the transform.Translate function to move the object of this script to the left at the speed of time.deltaTime multiplied by the speed variable. You can then duplicate this if statement once and change it to use the rightKey string and move the paddle to the right. This is the basic controls for the player’s paddle but we now have one problem. The paddle will keep moving even if it reaches the end of the playing field and camera view. To fix this add another “and” condition to your two if statements checking to see if the x position of the paddle is with a set boundary. Lastly, make sure to call your PaddleMovement function in the Update function of this script. 

In the end, this is what our version of the player controller script looks like.

PaddleController.cs

using UnityEngine;

public class PaddleController : MonoBehaviour
{
    public string leftKey, rightKey;
    public float speed;

    // Use this for initialization

    // Update is called once per frame
    void Update()
    {
        PaddleMovement();
    }

    void PaddleMovement()
    {
        if (Input.GetKey(leftKey) && transform.position.x > -4)
        {
            transform.Translate(Vector3.left * Time.deltaTime * speed, Space.World);
        }
        if (Input.GetKey(rightKey) && transform.position.x < 4)
        {
            transform.Translate(Vector3.right * Time.deltaTime * speed, Space.World);
        }
    }
}
using Photon.Chat;
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PhotonChatManager : MonoBehaviour, IChatClientListener
{
    #region Setup

    [SerializeField] GameObject joinChatButton;
    ChatClient chatClient;
    bool isConnected;
    [SerializeField] string username;

    public void UsernameOnValueChange(string valueIn)
    {
        username = valueIn;
    }

    public void ChatConnectOnClick()
    {
        isConnected = true;
        chatClient = new ChatClient(this);
        //chatClient.ChatRegion = "US";
        chatClient.Connect(PhotonNetwork.PhotonServerSettings.AppSettings.AppIdChat, PhotonNetwork.AppVersion, new AuthenticationValues(username));
        Debug.Log("Connenting");
    }

    #endregion Setup

    #region General

    [SerializeField] GameObject chatPanel;
    string privateReceiver = "";
    string currentChat;
    [SerializeField] InputField chatField;
    [SerializeField] Text chatDisplay;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (isConnected)
        {
            chatClient.Service();
        }

        if (chatField.text != "" &amp;&amp; Input.GetKey(KeyCode.Return))
        {
            SubmitPublicChatOnClick();
            SubmitPrivateChatOnClick();
        }
    }

    #endregion General

    #region PublicChat

    public void SubmitPublicChatOnClick()
    {
        if (privateReceiver == "")
        {
            chatClient.PublishMessage("RegionChannel", currentChat);
            chatField.text = "";
            currentChat = "";
        }
    }

    public void TypeChatOnValueChange(string valueIn)
    {
        currentChat = valueIn;
    }

    #endregion PublicChat

    #region PrivateChat

    public void ReceiverOnValueChange(string valueIn)
    {
        privateReceiver = valueIn;
    }

    public void SubmitPrivateChatOnClick()
    {
        if (privateReceiver != "")
        {
            chatClient.SendPrivateMessage(privateReceiver, currentChat);
            chatField.text = "";
            currentChat = "";
        }
    }

    #endregion PrivateChat

    #region Callbacks

    public void DebugReturn(DebugLevel level, string message)
    {
        //throw new System.NotImplementedException();
    }

    public void OnChatStateChange(ChatState state)
    {
        if(state == ChatState.Uninitialized)
        {
            isConnected = false;
            joinChatButton.SetActive(true);
            chatPanel.SetActive(false);
        }
    }

    public void OnConnected()
    {
        Debug.Log("Connected");
        joinChatButton.SetActive(false);
        chatClient.Subscribe(new string[] { "RegionChannel" });
    }

    public void OnDisconnected()
    {
        isConnected = false;
        joinChatButton.SetActive(true);
        chatPanel.SetActive(false);
    }

    public void OnGetMessages(string channelName, string[] senders, object[] messages)
    {
        string msgs = "";
        for (int i = 0; i &lt; senders.Length; i++)
        {
            msgs = string.Format("{0}: {1}", senders[i], messages[i]);

            chatDisplay.text += "\n" + msgs;

            Debug.Log(msgs);
        }

    }

    public void OnPrivateMessage(string sender, object message, string channelName)
    {
        string msgs = "";

        msgs = string.Format("(Private) {0}: {1}", sender, message);

        chatDisplay.text += "\n " + msgs;

        Debug.Log(msgs);
        
    }

    public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
    {
        throw new System.NotImplementedException();
    }

    public void OnSubscribed(string[] channels, bool[] results)
    {
        chatPanel.SetActive(true);
    }

    public void OnUnsubscribed(string[] channels)
    {
        throw new System.NotImplementedException();
    }

    public void OnUserSubscribed(string channel, string user)
    {
        throw new System.NotImplementedException();
    }

    public void OnUserUnsubscribed(string channel, string user)
    {
        throw new System.NotImplementedException();
    }

    #endregion Callbacks
}

Once you have this script written up we can then save it and go back to Unity.

You will now need to create a prefab for the paddle. The following objects are what constitute our paddle prefab

  • This is an empty object with the PlayerController script attached to it.
    • : This is a 2D sprite object with the paddle image as the sprite. It also has a Box Collider 2D attached to it.

Once you have created this object in your scene turn it into a prefab. First, create a new folder in your project window and call it Prefabs. Then select the topmost object of the paddle prefab and drag it from your hierarchy to the Prefabs folder.

To test your paddle prefab drag on more into your scene by selecting the paddle prefab from your project window and drag it into the hierarchy window. With this object select change the Z rotation of its transform to 180. This will rotate this object around to the other side of the playing field. Now, for the PlayerController script of this second paddle, you will need to change the values of the leftKey and rightKey variables (I suggest J and L).

Now you can click the play button and test your project so far. You should be able to move the bottom paddle back and forth using the A and D keys and the top paddle with J and L. 

Posted on

How to make Pong in Unity Lesson 1

Play Classic Pong

Welcome to the Info Gamer tutorial series and ebook on how to make your very own Pong Clone using Unity. In this ebook, we will take you step by step through all the key mechanics need to build the basic game of Pong. Along the way, we will explain the purpose of each step and what is possible so you can better understand and learn how to make video games.

If you are not familiar with Pong and would to play it first you can play our version here

Preparation

Things you will need

Before we begin there are a few things you will need. 

  • Computer
  • Internet connection
  • Unity Hub
  • Unity editor

If you are viewing this now then we can assume you already have a computer and an internet connection so you are already halfway there. I also assume you already have Unity Hub and a version of the Unity editor installed but if you don’t you can find our tutorial series on how to install Unity here

The version of Unity does not matter.

Once you have everything you need you will then need to create a new Unity project. You will want to use the 2D template. If you need help knowing how to create a new project follow this tutorial here






Once you have these images imported into your project we can then begin designing our scene. We have divided the game scene up into the following objects. (Click the links to see Inspector)

  • : Your empty scene should already have a camera game object called Main Camera. Make sure this object has the following inspector
  • Directional Light: This is another object that should already be in your empty scene. You don’t need to do anything with this object, in fact, you can just delete this object as we will only be using unlit sprites for this game.
  • Environment: This is a new empty object with the following children
    • : This is a sprite object with the black square sprite
    • : This is an empty object with a 2D box collider
    • LeftWall: This is the same as RightWall but with a negative X position.
    • : This is similar to RightWall and LeftWall but the size of the box collider and position are different.
    • EndTwo: This is the same as EndOne but the Y position is negative.
    • : This is a sprite object with the dotted line sprite.
  • : This is a UI canvas object with the following Canvas Scaler setting.
    • : Is a UI text object anchored to the bottom of the canvas with a 0 for the Text field.
    • ScoreTwo: This is the same a ScoreOne but it is anchored to the top of the canvas.
    • : This is another text object anchored to the bottom. This has the following string for the Text field. “< A           D >”
    • Player2Keys: This is the same as Player1Keys but this object is anchored to the top of the canvas and has the following string for its Text field. “< J           L >”
    • : This is a UI Panel object that has its image transparency turned down to zero.
      • : This is a UI Text object used for displaying the winner. The following string is the value of the Text field. “Player _ Wins”
      • : This is a UI Button object.
        • : This is the UI Text object that comes with the default UI Button.
    • EventSystem: This is the Event System object that is created by default when you create a UI Canvas

Note: Do not forget the tags

Here is what your hierarchy should look like.

Here is what your Game View should look like.

Note: Once you have all this created you can then disable the GameOverPanel in your hierarchy.

At this point, you should have the environment for your game scene complete.