Adding Timer in c#

Hello!

Im currently working on a basic game and its going well, the only thing I need to add is a timer. The game is made on the basic model of “Roll-a-Ball”.

I have a Player object and PickUp objects, there is 20 objects to pick up on the level.
What I would like here is a timer that starts at the beginning of the level (counting down from 20isch seconds). and adding 5 seconds every time the player picks up an object,
Then when all objects are collected the timer should stop and maybe play a big Guitext with the final time.

This is currently my PlayerController Script:

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour
{

   public float speed;
   public GUIText countText;
   public GUIText winText;
   private int count;

   void Start ()
   {
     count = 0;
     SetCountText ();
     winText.text = "";
   }

   void FixedUpdate ()
   {
     float moveHorizontal = Input.GetAxis("Horizontal");
     float moveVertical = Input.GetAxis("Vertical");

     Vector3 movement = new Vector3(moveHorizontal, 0, moveVertical);

     GetComponent<Rigidbody> ().AddForce (movement * speed * Time.deltaTime);
   }

   void OnTriggerEnter(Collider other)
   {
     if (other.gameObject.tag == "PickUp")
     {
       other.gameObject.SetActive (false);
       count = count + 1;
       SetCountText ();
     }
   }

   void SetCountText ()
   {
     countText.text = "Score: " + count.ToString();
     if (count >= 20)
     {
       winText.text = "YOU WIN!";
     }
   }
}

Is it possible to modify this or should I make a completely new Scripts for the timer?
Any help would be highly appriciated!

//Cheers

of course you can modifiy this script to track the time.

float timer;

void Start()
{
   timer = 20;
}

void Update()
{
   timer -= Time.deltaTime;
}

void OnTriggerEnter(Collider other)
{
   if(other.gameObject.tag == "Pickup")
   {
      timer += 5;
   }
}
1 Like

Thank you for the quick response vothka :slight_smile:

I managed to input the code into my script.
But I still need to make a GUItext to show the time and preferably make the timer stop when all pickup objects are collected, do you think you can help me with this?

Cheers again!

well as you know your scriptcomponents that inherit from Monobehaviour do not have a constructor. so you need to use Start or Awake to initialize your variables.

and Update is called every Frame automatically, so it makes sense to “update” your timer there.

So it does matter in which method you put it, but not necessarily in which line in this method - if that is your question.

to the part with the GUI. First i wouldn’t recommend using the OnGUI system at all. It is outdated for a good reason.
Instead try to get used to the new UI canvas system.

if you really do insist on using OnGUI() than i suggest using an enum that switches your gamestates. And a switch - case section in your OnGUI() Method that draws the corresponding GUI Elements that belong to each gamestate

edit:

sth like:

public enum EGameState
  {
    MAINMENU,
    RUNNING,
    PAUSED,
    WON,
    LOST
  }
  public EGameState m_gameState = EGameState.MAINMENU;

void OnGUI()
  {
    switch (m_gameState)
    {
      case EGameState.MAINMENU:
        break;
      case EGameState.RUNNING:
        break;
      case EGameState.PAUSED:
        break;
      case EGameState.WON:
        GUI.TextArea(new Rect(0, 0, 100, 100), "YOU WON");
        break;
      case EGameState.LOST:
        break;
      default:
        break;
    }
  }

if you would now switch your gamestate with your “win-condition” your textbox would also appear

Im gonna try this out, will there be some stuff in the scene I will have to change to adapt to this?

I’ll let you know more when I’ve tried it :slight_smile:

No. just triple check that the method’s name really is OnGUI() - these elements will not work if the name is not correct

I’m sorry, but I kinda have a hard time to keep up since I dont know how much of this works.
Im not used to Unity and dont know how to use the UI canvas, and with this example you gave me, I’m still not sure what I need to add/change in the scene.

I’m kind of confused tbh.
All I really wanted was the time to be shown somewhere, like the 2 other texts I have.
and then when the objects were collected for the timer to stop.

I’ve basically just added all the code you gave me into the script, but nothing more, dont really know what to do next.

again thanks for all your time!

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour
{
  //add
  private enum EGameState
  {
    RUNNING,
    WON,
    LOST
  }

  //add
  private EGameState m_gameState;

  public float speed;
  //remove
  //public GUIText countText;

  //remove
  //public GUIText winText;
  private int count;

  //add
  float timer;

  void Start()
  {
    count = 0;
    //add
    m_gameState = EGameState.RUNNING;
    //remove
    //winText.text = "";
 
    //add
    timer = 20;
  }

  //add
  void Update()
  {
    /* so if gamemode is Running we want to reduce the timer */
    if(m_gameState == EGameState.RUNNING)
      timer -= Time.deltaTime;

    /*and if the timer is 0 we want to end the game with a lost condition
     this would automatically draw the Lost text in the OnGUI function */
    if (timer <= 0)
      m_gameState = EGameState.LOST;
  }

  void FixedUpdate()
  {
   //you might also want to only process playerinput if the game is not already over
   if(m_gameState == EGameState.Running){
    float moveHorizontal = Input.GetAxis("Horizontal");
    float moveVertical = Input.GetAxis("Vertical");

    Vector3 movement = new Vector3(moveHorizontal, 0, moveVertical);

    GetComponent<Rigidbody>().AddForce(movement * speed * Time.deltaTime);
   }
  }

  void OnTriggerEnter(Collider other)
  {
    if (other.gameObject.tag == "PickUp")
    {
      other.gameObject.SetActive(false);
      count = count + 1;
      //add
      if(count >= 20)
        m_gameState = EGameState.WON;
    }
  }

  //remove
  /*
  void SetCountText()
  {
    countText.text = "Score: " + count.ToString();
    if (count >= 20)
    {
      winText.text = "YOU WIN!";
    }
  }*/


  //add
  void OnGUI()
  {
    switch (m_gameState)
    {
      case EGameState.RUNNING:
        GUI.Box(new Rect(0, 0, 100, 30), "Time Left: " + Mathf.Round(timer));
        GUI.Box(new Rect(0, 30, 100, 30), "Score: " + count);
        break;
      case EGameState.WON:
        GUI.Box(new Rect(Screen.width / 2, Screen.height / 2, 300, 30), "YOU WON and even had " + Mathf.Round(timer) + " Seconds left");
        break;
      case EGameState.LOST:
        GUI.Box(new Rect(Screen.width / 2, Screen.height / 2, 300, 30), "YOU LOST :( final Score: " + count);
        break;
      default:
        break;
    }
  }
}

this was kind of the way i wanted to suggest

Works really well, the only thing missing is adding 5 sec on pickup. but it doesnt really matter, this is amazing!
Thank you for all your trouble and sorry if I seem a bit slow, like I said. I am completely new to this :slight_smile:

no problem at all, glad i could help

i assume you figuered out where to add the 5seconds on your own already?

click me Line 72: timer += 5;

1 Like

If you need a handy timer class you can use mine:

using UnityEngine;
using System.Collections;

public class InternalTimer
{
    public System.Action OnCompleted;
    public System.Action<float> OnProgress;

    public float time = 5f;
    public bool enabled = true;
    public bool oneTime = false;

    private float m_internalTimer = 0f;

    public InternalTimer(float aTime)
    {
        time = aTime;
    }

    public bool Tick()
    {
        if (!enabled)
            return false;

        m_internalTimer += Time.deltaTime;

        if (OnProgress != null)
            OnProgress(Mathf.Clamp01(m_internalTimer / time));

        if (m_internalTimer >= time)
        {
            Reset();
            if (oneTime)
                enabled = false;

            if (OnCompleted != null)
                OnCompleted();

            return true;
        }

        return false;
    }

    public void Reset()
    {
        m_internalTimer = 0;
    }
}

So basically you create the timer instance within Start() method:

public timeNeeded = 5f;

private InternalTimer m_timer;

void Start()
{
     m_timer = new Timer( timeNeeded );
}

Then you put it inside your Update() method to invoke Tick() method:

void Update()
{
     if ( m_timer.Tick() )
     {
          Debug.Log("Do something! "+ timeNeeded+" seconds passed!");
     }
}

And that’s about it. You can also set it to be one time or use actions if you’re feeling lucky:

void Start()
{
     m_timer.OnComplete = delegate()
     {
          Debug.Log("Timer done");
     };

     m_timer.OnProgress = delegate(float progress)
     {
          Debug.Log(progress * 100 + "% done");
     };
     
     m_timer.oneTime = true;

     //if you need to disable it; if oneTime = true this will set to false
     m_timer.enabled = false;
}

Just remember to call Tick() in your update method. Hope this helps someone!

1 Like

Thank you so much for all your time Vothka, it is greatly appriciated!
this was exactly what I needed :):slight_smile:

thank you aswell fajlworks! I will look into it!