Search Unity

Timer

Discussion in 'Getting Started' started by Laur155, Dec 27, 2018.

  1. Laur155

    Laur155

    Joined:
    Mar 2, 2017
    Posts:
    30
    Hello i am trying to create a timer but i dont want to use the previous and next lines,so i can not check the Time.time every frame with Update because it will do the previous lines,also i can not use the WaitForSeconds() because it will not stop once per frame.What i want is something like this.
    I hope that you can understand.
    Thank you!
    Code (CSharp):
    1. void Update(){
    2. //Do A
    3. //Do B
    4.  
    5. //Wait some time
    6.  
    7. //Do C
    8. //Do D
    9.  
    10. //Repeat for the next frame
    11. }
     
  2. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,512
    Coroutines are the way to go. If you're using .NET 4.x, you can use async-await, but you can run into problems with thread safety. So for something simple like a timer, I stick with a combination of Update to get the deltaTime and a coroutine to update the UI (so that it's not being updated needlessly 60 times a second.

    A simple timer could look like this:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class GameTimer : MonoBehaviour {
    7.     public bool isGameActive;
    8.     private float gameTime;
    9.     private Text txtTimer;
    10.     private WaitForSeconds updateInterval = new WaitForSeconds (0.25f);
    11.  
    12.     void Awake () {
    13.         txtTimer = GetComponent<Text> ();
    14.         StartCoroutine (UpdateTimerText ());
    15.     }
    16.  
    17.     void Update () {
    18.         if (isGameActive) {
    19.             gameTime += Time.deltaTime;
    20.         }
    21.     }
    22.  
    23.     private IEnumerator UpdateTimerText () {
    24.         while (isGameActive) {
    25.             txtTimer.text = gameTime; // Optionally, format it to look nice
    26.             yield return updateInterval;
    27.         }
    28.     }
    29. }
     
  3. Laur155

    Laur155

    Joined:
    Mar 2, 2017
    Posts:
    30
    Sorry i did not explain it very well what i want.If i use the following code it will have this results http://prntscr.com/m0pkck i guess that is because when it calls the coroutine the update still goes on,so even if i have it in the coroutine the Debugs the previous and the next commands will be excecuted and i dont want that.Once it excecutes the Debug.Log("A"); i want it to stop(no more excecutaion of this or other frames) here in the code the A,B ahve the same time.
    Thank you!
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WCam : MonoBehaviour {
    6.    
    7.  
    8.     // Update is called once per frame
    9.     void Update() {
    10.         Debug.Log("A");
    11.         StartCoroutine(Test());
    12.         Debug.Log("B");
    13.     }
    14.  
    15.    
    16.     public IEnumerator Test()
    17.     {
    18.         yield return new WaitForSeconds(5);
    19.     }
    20. }
    21.  
     
  4. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,512
    Compare your code to the one I shared. You do not want to start a coroutine from within the Update method, as Update gets called 60 times per second. That's why I kick it off from within Awake, which happens only once when the component is first activated.
     
  5. Laur155

    Laur155

    Joined:
    Mar 2, 2017
    Posts:
    30
    Thanks a lot that works!:)
     
  6. Laur155

    Laur155

    Joined:
    Mar 2, 2017
    Posts:
    30
    Sorry only one more question,what i do if what to do it on a scecific times like if the user press A then stop else dont do anything.Like Debug.Log("A"); Debug.Log("B"); /wait 5s/ Debug.Log("C"); Debug.Log("D");
    Thank you!
     
  7. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,512
    I'm not sure what you mean. Like start and stop the timer based on what keys are pressed?
     
  8. Laur155

    Laur155

    Joined:
    Mar 2, 2017
    Posts:
    30
    in each frame i want the timer to start and stop the flow of the programm until the timer ends and when this happen the flow of the programm will continue from the next line of code.
     
  9. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,512
    I'm still not sure what you're going for here. Could you be more specific about what your end goal is? I suspect there's a different way to do it that may be easier and more in line with got Unity works.
     
  10. Laur155

    Laur155

    Joined:
    Mar 2, 2017
    Posts:
    30
    Yeah i am not really good with english.:(
    May this example will make it a litle bit clear and tell where is my probel with the coroutine.
    Assume some lines #n of code that are excecuted each frame.In the line A<n the cube1 in moved in the x axis by 5 then the program stops for 5s and in the next line the cube2 in moved the same directrion then the rest of the code.If use a coroutine,when it goes there it will start the coroutine it excecutes her but continues the rest lines of the code and so the frame ends and goes back at the top of the code.

    Or maybe this will hep

    for(EveryFrame){
    Move cube1
    Stop for 5s
    Move cube2
    }
     
  11. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,512
    I didn't test this, but this should get you going in the right direction:
    Code (CSharp):
    1. public GameObject cube1;
    2. public GameObject cube2;
    3.  
    4. public Vector3 cube1EndPos;
    5. public Vector3 cube2EndPos;
    6.  
    7. private float cubeMoveTime = 1.0f;      // How long it should take to move cube
    8. private float pauseTime = 3.0f;         // How long to wait between cube movements
    9. private WaitForEndOfFrame yieldFrame = new WaitForEndOfFrame ();
    10.  
    11. public MoveCubes() {
    12.     StartCoroutine(AnimRotate());
    13. }
    14.  
    15. public IEnumerator AnimRotate () {
    16.     float elapsedTime = 0f;
    17.     Vector3 startPos = cube1.transform.position;
    18.  
    19.     while (elapsedTime < cubeMoveTime) {
    20.         cube1.transform.position = Vector3.Lerp (startPos, cube1EndPos, (elapsedTime / cubeMoveTime));
    21.         elapsedTime += Time.deltaTime;
    22.         yield return yieldFrame;
    23.     }
    24.     elapsedTime = 0f;   // Reset to prepare for next timer
    25.    
    26.     yield return new WaitForSeconds(pauseTime); // Pause for desired amount of time
    27.    
    28.     Vector3 startPos = cube2.transform.position;    // Reset start pos for second cube
    29.     while (elapsedTime < cubeMoveTime) {
    30.         cube2.transform.position = Vector3.Lerp (startPos, cube2EndPos, (elapsedTime / cubeMoveTime));
    31.         elapsedTime += Time.deltaTime;
    32.         yield return yieldFrame;
    33.     }
    34.  
    35.     Debug.Log("All finished moving cubes");
    36. }
    Obviously if you want this to be dynamic, you'll want it to be a bit more robust and generic, where you can pass objects and positions in and stuff.
     
  12. Laur155

    Laur155

    Joined:
    Mar 2, 2017
    Posts:
    30
    The're was onew error but its a lead to what i want thanks!