THE ROAD RUNNER TUTORIAL 10: ADDING COUNTDOWN AND MAIN MENU

Check out the gameplay of the finished game below:



This is going to be a quick post on how to add a main menu, which will be the first scene that the user will see just like any other game.
We will also add a countdown so as the user gets sufficient amount of time to get a feel of the game environment.
So lets get started!

The first thing that you want to do is to create a new C# script named CountdownScript in the scripts folder. Attach this script to the GameController gameobject.

Now, it looks like a daunting task, the addition of the Countdown Timer. In a way it is, yeah, because we need to disable all the scripts, that we have created so far, as long as the count is not down. But yeah, we are no losers! Let's just do it. And once you do this, you will know how easy it was. High-Five!

We need to define the references of all the gameobjects so as to get their components to disable/enable based on our requirements.

public GameObject character;
public GameObject wall1;
public GameObject wall2;
public GameObject ground;
public int countMax;  //max countdown number
private int countDown;  //current countdown number
public GUIText guiTextCountdown;//GUIText reference

The countMax lets you define the number from which you want to start the countdown. countDown holds the current countdown number. guiTextCountdown holds the GUIText component which we will be adding to the game scene later.

The Start function is where all the initialization is done and it look like

void Start () {
  MonoBehaviour[] scriptComponentsGameControl = gameObject.GetComponents<MonoBehaviour>();   //get all the script components attached
  //loop through all the scripts and disable them
  foreach(MonoBehaviour script in scriptComponentsGameControl) {
   script.enabled = false;
  }

  //disable all the scripts attached to the walls, ground. Also disable the animation of character
  wall1.GetComponent<GroundControl>().enabled = false;
  wall2.GetComponent<GroundControl>().enabled = false;
  ground.GetComponent<GroundControl>().enabled = false;
  character.GetComponent<Animation>().enabled = false;

  //Call the CountdownFunction
  StartCoroutine(CountdownFunction());
 }

There is quite a bit of code here, actually. Some terms might seem new to you, but yes this is no Rocket Science though.

Since we have attached this script to the GameController gameobject, we dont need to add a reference to it, unlike the other gameobjects. That is precisely why we are using the term gameObject when getting it's components, while we are using the references to get the components of other gameobjects.

MonoBehaviour type components are nothing but the scripts that we have written earlier. Since there are more than one scripts attached to the GameController gameobject, we are using the general term MonoBehaviour, to get the scripts, unlike in the other gameobjects, where we are specifying the script names to get and disable them.

Further down the lines you see that we are calling a function named CountdownFunction alright, but why is it enclosed in StartCoroutine, peculiar eh!
Well, we will come to it later.

The CountdownFunction is where the logic of this script lies.

IEnumerator CountdownFunction() {
  //start the countdown
  for(countDown = countMax; countDown>-1;countDown--){
   if(countDown!=0){
    //display the number to the screen via the GUIText
    guiTextCountdown.text = countDown.ToString();
    //add a one second delay
    yield return new WaitForSeconds(1);    
   }
   else{
    guiTextCountdown.text = "GO!";
    yield return new WaitForSeconds(1);
   }
  }
  //enable all the scripts and animation once the count is down
  MonoBehaviour[] scriptComponentsGameControl = gameObject.GetComponents<MonoBehaviour>();   
  foreach(MonoBehaviour script in scriptComponentsGameControl) {
   script.enabled = true;
  }

  wall1.GetComponent<GroundControl>().enabled = true;
  wall2.GetComponent<GroundControl>().enabled = true;
  ground.GetComponent<GroundControl>().enabled = true;
  character.GetComponent<Animation>().enabled = true;
  //disable the GUIText once the countdown is done with
  guiTextCountdown.enabled = false;
 }

"Wait, wait! Now, you didn't explain what StartCoroutine was and now you are using this IEnumerator as the return type of this function. What's going on?" These might be your question, I'm guessing.

Well, let me clear that for you now.
StartCoroutine basically starts a coroutine, Coroutines are functions where in you can pause the execution at any point in time using the Yield statement.
The IEnumerator allows the program to yield things like the WaitForSeconds function, which lets you tell the script to wait without hogging the CPU.
The yield statement is a special kind of return, that ensures that the function will continue from the line after the yield statement

So, in brief, if you want to add a delay in your script execution, call the delay function from enclosed in a StartCoroutine, and that delay function should have a return type of IEnumerator i.e. wherever you have yield, it's return type should be IEnumerator.

Once, the count is down we enable all the scripts disabled. We also disable the GUIText.

The complete CountdownScript is as below

using UnityEngine;
using System.Collections;

public class CountdownScript : MonoBehaviour {

 public GameObject character;
 public GameObject wall1;
 public GameObject wall2;
 public GameObject ground;

 public int countMax;  //max countdown number
 private int countDown;  //current countdown number
 public GUIText guiTextCountdown;//GUIText reference
 // Use this for initialization
 void Start () {
  MonoBehaviour[] scriptComponentsGameControl = gameObject.GetComponents<MonoBehaviour>();   //get all the script components attached
  //loop through all the scripts and disable them
  foreach(MonoBehaviour script in scriptComponentsGameControl) {
   script.enabled = false;
  }

  //disable all the scripts attached to the walls, ground. Also disable the animation of character
  wall1.GetComponent<GroundControl>().enabled = false;
  wall2.GetComponent<GroundControl>().enabled = false;
  ground.GetComponent<GroundControl>().enabled = false;
  character.GetComponent<Animation>().enabled = false;

  //Call the CountdownFunction
  StartCoroutine(CountdownFunction());
 }
 
 // Update is called once per frame
 void Update () {

  }

 IEnumerator CountdownFunction() {
  //start the countdown
  for(countDown = countMax; countDown>-1;countDown--){
   if(countDown!=0){
    //display the number to the screen via the GUIText
    guiTextCountdown.text = countDown.ToString();
    //add a one second delay
    yield return new WaitForSeconds(1);    
   }
   else{
    guiTextCountdown.text = "GO!";
    yield return new WaitForSeconds(1);
   }
  }
  //enable all the scripts and animation once the count is down
  MonoBehaviour[] scriptComponentsGameControl = gameObject.GetComponents<MonoBehaviour>();   
  foreach(MonoBehaviour script in scriptComponentsGameControl) {
   script.enabled = true;
  }

  wall1.GetComponent<GroundControl>().enabled = true;
  wall2.GetComponent<GroundControl>().enabled = true;
  ground.GetComponent<GroundControl>().enabled = true;
  character.GetComponent<Animation>().enabled = true;
  //disable the GUIText once the countdown is done with
  guiTextCountdown.enabled = false;
 }
}

Create a GUIText by going to GameObject->Create Other->GUI Text, name it as guiCountdown, position it at (0.5, 0.8, 0)
Add a font to the GUIText. Change the size to, say, 40. Choose the color you wish to.


Now, we need to define the gameobjects for the references in the CountdownScript. Drag the gameobjects in their respective fields as in the image below;


Also, give the count max a value of 3.

This is pretty much it. If you play the game, you will notice that the countdown works just about perfect.

I started with saying a Quick Post, and ended up with perhaps the lengthiest post of this series. It's not over though. We still have to add the main menu.

Save the current scene by using ctrl+s on Windows and cmd+s on the Mac. Go to File->New Scene or simply press ctrl+n/cmd+n, to create a new scene. Save the scene and name it as MainMenuScene.

Add a GUIText to display the name of our game. Position it wherever you like, I prefer it at (0.35, 0.9, 0)
Fill the Text field with the name of our game i.e The Road Runner, set the font size to 40, add a font material as well.


If you want to further enrich the scene, you can add the character as well and give it a default idle animation, and of course remove all the scripts.

Create a new C# script named MainMenuScript, attach it to the Main Camera. The script will look very much like the other menu scripts.

using UnityEngine;
using System.Collections;

public class MainMenuScript : MonoBehaviour 
{
 public GUISkin myskin;  //custom GUIskin reference
 public string gameLevel;
 public string optionsLevel;

 private void OnGUI()
 {
  GUI.skin=myskin;   //use the custom GUISkin
   
   GUI.Box(new Rect(Screen.width/4, Screen.height/4, Screen.width/2, Screen.height/2), "MAIN MENU");
   
   if (GUI.Button(new Rect(Screen.width/4+10, Screen.height/4+Screen.height/10+10, Screen.width/2-20, Screen.height/10), "PLAY")){
    Application.LoadLevel(gameLevel);
   }
   
   if (GUI.Button(new Rect(Screen.width/4+10, Screen.height/4+2*Screen.height/10+10, Screen.width/2-20, Screen.height/10), "CREDITS")){
   Application.LoadLevel(optionsLevel);
   }
   
   if (GUI.Button(new Rect(Screen.width/4+10, Screen.height/4+3*Screen.height/10+10, Screen.width/2-20, Screen.height/10), "EXIT")){
    Application.Quit();
   }
 }
}

Save the script. Add the GUI skin. Name the scene to open on clicking the Play button. You can also create other scenes like Credits, Options, Instructions and others. and add that to the menu as well.


Now test the game and feel free to customize it as per your needs.


Download the completed version of this game from the Resources page.

The Road Runner Tutorial 1: Setting Up The World
The Road Runner Tutorial 2: Setting Up The World Continued
The Road Runner Tutorial 3: Adding A Character To Our Game
The Road Runner Tutorial 4: Set The Ground Moving
The Road Runner Tutorial 5: Adding Snags and Powerups to Our Game
The Road Runner Tutorial 6: Collecting The Snags and Powerups
The Road Runner Tutorial 7: Adding Gameplay Logic
The Road Runner Tutorial 8: Creating a Custom GUI Skin
The Road Runner Tutorial 9: Creating a Pause Menu
The Road Runner Tutorial 11: Adding Sound Effects To Our Game
The Road Runner Tutorial 12: Porting The Game To Android
Share on Google+

About Sujit Horakeri

Sujit Horakeri is a game freak just like any other next door guy you would come across. He is a Web Developer by Profession, Game Developer by Choice.
Connect with him on:
    Blogger
    Facebook

26 comments:

  1. Its not counting down its just makes the game crash there will be no power up or obstacles to get and keep when play the GUI TEXT up the builder

    ReplyDelete
  2. Replies
    1. Well, maybe delete the changes you have made. Check if it works fine and follow this post step by step. Maybe you have missed something somewhere

      Delete
  3. Sujit Horakeri thanks for the help in the previous posts, i fixed everything =D
    But now i am having another problem, when i click Play in the "MainMenuScene" to start the game i get this error

    "Level 'main' (-1) couldn't be loaded because it has not been added to the build settings.
    To add a level to the build settings use the menu File->Build Settings...
    UnityEngine.Application:LoadLevel(String)"

    i try to change my other scene with the name "gameLevel" but didnt work.
    waiting for response, thanks :)

    ReplyDelete
    Replies
    1. i changed gameLevel in the script for 1 and worked hehe :)

      Delete
  4. i m having the same problm...what would i do

    ReplyDelete
  5. Replies
    1. Please be precise of what your problem is, so that we can be of any help..What exactly is the issue you are facing?

      Delete
    2. When you press exit it doesn't quit the game.

      Delete
  6. Why do the power up and obstacles move during the count down? Is the script missing something to disable them until after the count down?

    ReplyDelete
  7. first i would like to thank you for this great tutorial

    i have the new version of unity and they change the GUI system,
    i try to add Text from the new UI menu but it refuse to be added as a GUI Text Countdown, can you help me with this?

    and thanks again.

    ReplyDelete
  8. Hey mate, thanls for the awesome tutorial its taught me a lot! :) but I do have a problem, regarding the main menu, It works fine but I can't hit play, options, or anything. I think it could be a reference problem, but i dont know here to start.

    Cheers mate.

    ReplyDelete
    Replies
    1. You need to add all your scenes in the Build Settings. TO do this go to FILE->BUILD SETTINGS. Drag and drop the all scenes which you want in your game

      Delete
  9. The ground is still moving even on countdown , can you please help?

    ReplyDelete
  10. nvm i found out that the script was added two times :D

    ReplyDelete
  11. i have unity 4.6.....there is no Game object like GUI text
    it has UI ->Text....and when select it then it comes with a canvas...i m not understanding wat can i do now....i ant scale or tranform it...pls help me

    ReplyDelete
    Replies
    1. You can add a GUI text by creating an empty game object and going to Inspector-> Add component-> Search Guitext...

      Delete
  12. I'm having the same problem. There is no GUI Text in update 4.6

    ReplyDelete
    Replies
    1. You can add a GUI text by creating an empty game object and going to Inspector-> Add component-> Search Guitext...

      Delete
  13. hi sir when i press play button it doesnt start game why pls help me

    ReplyDelete
  14. MonoBehaviour[] scriptComponentsGameControl = gameObject.GetComponents(); //get all the script components attached
    //loop through all the scripts and disable them
    foreach(MonoBehaviour script in scriptComponentsGameControl) {
    script.enabled = false;
    }

    ReplyDelete
    Replies
    1. unity3d has problem with that codes because of using monobehaviours like that.

      Delete
  15. hai its is a great tutorial,but i have a problem with gui text ,when I hit the play button countdown is not showing but the scrips are deattatched and attatched after that 3 seconds please help me

    ReplyDelete
  16. I did just as u ,but when i press play it saying that the "Level '1' (-1) couldn't be loaded because it has not been added to the build settings." I added the scene in the build setting but it's not starting the game.

    ReplyDelete
  17. CountdownScript is notloading up in unity although it is totally fine

    ReplyDelete