Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Adding Timer in c#

Discussion in 'Scripting' started by Swiftbanana, Apr 20, 2015.

  1. Swiftbanana

    Swiftbanana

    Joined:
    Apr 6, 2015
    Posts:
    8
    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:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class PlayerController : MonoBehaviour
    6. {
    7.  
    8.    public float speed;
    9.    public GUIText countText;
    10.    public GUIText winText;
    11.    private int count;
    12.  
    13.    void Start ()
    14.    {
    15.      count = 0;
    16.      SetCountText ();
    17.      winText.text = "";
    18.    }
    19.  
    20.    void FixedUpdate ()
    21.    {
    22.      float moveHorizontal = Input.GetAxis("Horizontal");
    23.      float moveVertical = Input.GetAxis("Vertical");
    24.  
    25.      Vector3 movement = new Vector3(moveHorizontal, 0, moveVertical);
    26.  
    27.      GetComponent<Rigidbody> ().AddForce (movement * speed * Time.deltaTime);
    28.    }
    29.  
    30.    void OnTriggerEnter(Collider other)
    31.    {
    32.      if (other.gameObject.tag == "PickUp")
    33.      {
    34.        other.gameObject.SetActive (false);
    35.        count = count + 1;
    36.        SetCountText ();
    37.      }
    38.    }
    39.  
    40.    void SetCountText ()
    41.    {
    42.      countText.text = "Score: " + count.ToString();
    43.      if (count >= 20)
    44.      {
    45.        winText.text = "YOU WIN!";
    46.      }
    47.    }
    48. }
    49.  
    50.  
    ----

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

    //Cheers
     
  2. vothka

    vothka

    Joined:
    Mar 27, 2015
    Posts:
    59
    of course you can modifiy this script to track the time.
    Code (CSharp):
    1. float timer;
    2.  
    3. void Start()
    4. {
    5.    timer = 20;
    6. }
    7.  
    8. void Update()
    9. {
    10.    timer -= Time.deltaTime;
    11. }
    12.  
    13. void OnTriggerEnter(Collider other)
    14. {
    15.    if(other.gameObject.tag == "Pickup")
    16.    {
    17.       timer += 5;
    18.    }
    19. }
     
    Swiftbanana likes this.
  3. Swiftbanana

    Swiftbanana

    Joined:
    Apr 6, 2015
    Posts:
    8
    Thank you for the quick response vothka :)

    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!
     
    Last edited: Apr 20, 2015
  4. vothka

    vothka

    Joined:
    Mar 27, 2015
    Posts:
    59
    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:

    Code (CSharp):
    1. public enum EGameState
    2.   {
    3.     MAINMENU,
    4.     RUNNING,
    5.     PAUSED,
    6.     WON,
    7.     LOST
    8.   }
    9.   public EGameState m_gameState = EGameState.MAINMENU;
    10.  
    11. void OnGUI()
    12.   {
    13.     switch (m_gameState)
    14.     {
    15.       case EGameState.MAINMENU:
    16.         break;
    17.       case EGameState.RUNNING:
    18.         break;
    19.       case EGameState.PAUSED:
    20.         break;
    21.       case EGameState.WON:
    22.         GUI.TextArea(new Rect(0, 0, 100, 100), "YOU WON");
    23.         break;
    24.       case EGameState.LOST:
    25.         break;
    26.       default:
    27.         break;
    28.     }
    29.   }
    30.  
    if you would now switch your gamestate with your "win-condition" your textbox would also appear
     
    Last edited: Apr 20, 2015
  5. Swiftbanana

    Swiftbanana

    Joined:
    Apr 6, 2015
    Posts:
    8
    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 :)
     
  6. vothka

    vothka

    Joined:
    Mar 27, 2015
    Posts:
    59
    No. just triple check that the method's name really is OnGUI() - these elements will not work if the name is not correct
     
  7. Swiftbanana

    Swiftbanana

    Joined:
    Apr 6, 2015
    Posts:
    8
    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!
     
  8. vothka

    vothka

    Joined:
    Mar 27, 2015
    Posts:
    59
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerController : MonoBehaviour
    5. {
    6.   //add
    7.   private enum EGameState
    8.   {
    9.     RUNNING,
    10.     WON,
    11.     LOST
    12.   }
    13.  
    14.   //add
    15.   private EGameState m_gameState;
    16.  
    17.   public float speed;
    18.   //remove
    19.   //public GUIText countText;
    20.  
    21.   //remove
    22.   //public GUIText winText;
    23.   private int count;
    24.  
    25.   //add
    26.   float timer;
    27.  
    28.   void Start()
    29.   {
    30.     count = 0;
    31.     //add
    32.     m_gameState = EGameState.RUNNING;
    33.     //remove
    34.     //winText.text = "";
    35.  
    36.     //add
    37.     timer = 20;
    38.   }
    39.  
    40.   //add
    41.   void Update()
    42.   {
    43.     /* so if gamemode is Running we want to reduce the timer */
    44.     if(m_gameState == EGameState.RUNNING)
    45.       timer -= Time.deltaTime;
    46.  
    47.     /*and if the timer is 0 we want to end the game with a lost condition
    48.      this would automatically draw the Lost text in the OnGUI function */
    49.     if (timer <= 0)
    50.       m_gameState = EGameState.LOST;
    51.   }
    52.  
    53.   void FixedUpdate()
    54.   {
    55.    //you might also want to only process playerinput if the game is not already over
    56.    if(m_gameState == EGameState.Running){
    57.     float moveHorizontal = Input.GetAxis("Horizontal");
    58.     float moveVertical = Input.GetAxis("Vertical");
    59.  
    60.     Vector3 movement = new Vector3(moveHorizontal, 0, moveVertical);
    61.  
    62.     GetComponent<Rigidbody>().AddForce(movement * speed * Time.deltaTime);
    63.    }
    64.   }
    65.  
    66.   void OnTriggerEnter(Collider other)
    67.   {
    68.     if (other.gameObject.tag == "PickUp")
    69.     {
    70.       other.gameObject.SetActive(false);
    71.       count = count + 1;
    72.       //add
    73.       if(count >= 20)
    74.         m_gameState = EGameState.WON;
    75.     }
    76.   }
    77.  
    78.   //remove
    79.   /*
    80.   void SetCountText()
    81.   {
    82.     countText.text = "Score: " + count.ToString();
    83.     if (count >= 20)
    84.     {
    85.       winText.text = "YOU WIN!";
    86.     }
    87.   }*/
    88.  
    89.  
    90.   //add
    91.   void OnGUI()
    92.   {
    93.     switch (m_gameState)
    94.     {
    95.       case EGameState.RUNNING:
    96.         GUI.Box(new Rect(0, 0, 100, 30), "Time Left: " + Mathf.Round(timer));
    97.         GUI.Box(new Rect(0, 30, 100, 30), "Score: " + count);
    98.         break;
    99.       case EGameState.WON:
    100.         GUI.Box(new Rect(Screen.width / 2, Screen.height / 2, 300, 30), "YOU WON and even had " + Mathf.Round(timer) + " Seconds left");
    101.         break;
    102.       case EGameState.LOST:
    103.         GUI.Box(new Rect(Screen.width / 2, Screen.height / 2, 300, 30), "YOU LOST :( final Score: " + count);
    104.         break;
    105.       default:
    106.         break;
    107.     }
    108.   }
    109. }

    this was kind of the way i wanted to suggest
     
    Last edited: Apr 20, 2015
  9. Swiftbanana

    Swiftbanana

    Joined:
    Apr 6, 2015
    Posts:
    8
    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 :)
     
  10. vothka

    vothka

    Joined:
    Mar 27, 2015
    Posts:
    59
    no problem at all, glad i could help

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

    Line 72:
    Code (CSharp):
    1. timer += 5;
     
    Swiftbanana likes this.
  11. Fajlworks

    Fajlworks

    Joined:
    Sep 8, 2014
    Posts:
    344
    If you need a handy timer class you can use mine:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class InternalTimer
    5. {
    6.     public System.Action OnCompleted;
    7.     public System.Action<float> OnProgress;
    8.  
    9.     public float time = 5f;
    10.     public bool enabled = true;
    11.     public bool oneTime = false;
    12.  
    13.     private float m_internalTimer = 0f;
    14.  
    15.     public InternalTimer(float aTime)
    16.     {
    17.         time = aTime;
    18.     }
    19.  
    20.     public bool Tick()
    21.     {
    22.         if (!enabled)
    23.             return false;
    24.  
    25.         m_internalTimer += Time.deltaTime;
    26.  
    27.         if (OnProgress != null)
    28.             OnProgress(Mathf.Clamp01(m_internalTimer / time));
    29.  
    30.         if (m_internalTimer >= time)
    31.         {
    32.             Reset();
    33.             if (oneTime)
    34.                 enabled = false;
    35.  
    36.             if (OnCompleted != null)
    37.                 OnCompleted();
    38.  
    39.             return true;
    40.         }
    41.  
    42.         return false;
    43.     }
    44.  
    45.     public void Reset()
    46.     {
    47.         m_internalTimer = 0;
    48.     }
    49. }
    So basically you create the timer instance within Start() method:
    Code (CSharp):
    1. public timeNeeded = 5f;
    2.  
    3. private InternalTimer m_timer;
    4.  
    5. void Start()
    6. {
    7.      m_timer = new Timer( timeNeeded );
    8. }
    Then you put it inside your Update() method to invoke Tick() method:
    Code (CSharp):
    1. void Update()
    2. {
    3.      if ( m_timer.Tick() )
    4.      {
    5.           Debug.Log("Do something! "+ timeNeeded+" seconds passed!");
    6.      }
    7. }
    And that's about it. You can also set it to be one time or use actions if you're feeling lucky:
    Code (CSharp):
    1. void Start()
    2. {
    3.      m_timer.OnComplete = delegate()
    4.      {
    5.           Debug.Log("Timer done");
    6.      };
    7.  
    8.      m_timer.OnProgress = delegate(float progress)
    9.      {
    10.           Debug.Log(progress * 100 + "% done");
    11.      };
    12.      
    13.      m_timer.oneTime = true;
    14.  
    15.      //if you need to disable it; if oneTime = true this will set to false
    16.      m_timer.enabled = false;
    17. }
    Just remember to call Tick() in your update method. Hope this helps someone!
     
    Swiftbanana likes this.
  12. Swiftbanana

    Swiftbanana

    Joined:
    Apr 6, 2015
    Posts:
    8
    Thank you so much for all your time Vothka, it is greatly appriciated!
    this was exactly what I needed :):)

    thank you aswell fajlworks! I will look into it!