Search Unity

How would you guys go about making timers?

Discussion in 'Editor & General Support' started by Steamc0re, Dec 23, 2014.

  1. Steamc0re

    Steamc0re

    Joined:
    Nov 24, 2014
    Posts:
    144
    How would you guys go about making timers?

    For instance, I have a lot of things that need to happen only a certain amount of time after an object is instantiated, and if and when it does happen, I would imagine that checking the time.time every frame is bad.

    What I'm doing right now is (paraphrased)

    Code (CSharp):
    1. private float birthtime;
    2.  
    3. void Start() { birthtime = Time.time +3f; }
    4.  
    5. void Update(){
    6. if (Time.time > birthtime){
    7. doWhatever();
    8. }
    9. }
    So that will doWhatever after 3 seconds, but even after it does whatever, it's still checking the damn time every frame. If I have dozens of GO's that are doing this every frame, I imagine that's bad. So, what is the normal way to do timers? Is it to spawn a GO that has this timer in it, then sends the signal when the condition is met, and then kills itself to conserve resources? So, custom timer objects?
     
  2. JFo

    JFo

    Joined:
    Dec 9, 2007
    Posts:
    217
  3. dterbeest

    dterbeest

    Joined:
    Mar 23, 2012
    Posts:
    389
    The OOP way

    Timer class:
    Code (csharp):
    1.  
    2. public class Timer: MonoBehaviour {
    3.   private float _length;
    4.   private float _start;
    5.   private bool _isRunning = false;
    6.   private IWithTimer _sender;
    7.  
    8.   public void StartTimer(float len, IWithTimer sender) {
    9.     _length = len;
    10.     _start = Time.time;
    11.     _isRunning = true;
    12.   }
    13.  
    14.   void Update() {
    15.     if (_isRunning) {
    16.       if (_start + _length < Time.time) {
    17.         _isRunning = false;
    18.         _sender.TimerComplete(this);
    19.       }
    20.     }
    21.   }
    22. }
    23.  
    Interface for callback
    Code (csharp):
    1.  
    2. public interface IWithTimer {
    3.   void TimerComplete(Timer timer);
    4. }
    5.  
    Code (csharp):
    1.  
    2. public class SomeGameObject: MonoBehaviour, IWithTimer {
    3.   void Foo() {
    4.     Timer myTimer = GameManager.Instance.CreateTimer();
    5.     myTimer.StartTimer(3.5f, this)
    6.   }
    7.   public void TimerComplete(Timer timer) {
    8.     //DoStuff();
    9.   }
    10. }
    11.  
    And then there is offcourse Coroutines

    Code (csharp):
    1.  
    2. IEnumerator DoTimer() {
    3.   yield return new WaitForSeconds(3.5f);
    4.   //DoStuff();
    5. }
    6.  
    7. void Update() {
    8.   if (shouldStartATimer) {
    9.     StartCoroutine("DoTimer");
    10.   }
    11. }
    12. [code]
     
  4. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,261
    Little ambiguous with the line
    Code (CSharp):
    1. Timer myTimer = GameManager.Instance.CreateTimer();
    What is it doing to create the timer?
    How do you get rid of the timer after you are done with it?

    I do like the implementation and plan on using something like this when I need to start using timers.

    As for the OP's problem a simple boolean will stop it from running the timer.

    Code (CSharp):
    1. private float birthtime;
    2. private boolean runTimer;
    3.    
    4. void Start()
    5. {
    6.      birthtime = Time.time +3f;
    7.      runTimer = true;
    8. }
    9.    
    10. void Update()
    11. {
    12.     if (runTimer && Time.time > birthtime)
    13.     {
    14.          runTimer = false;
    15.          doWhatever();
    16.     }
    17. }
    18.  
    as long as the GO is 'alive' than Update will be called so you can't stop it from running without disabling or destroying the GO. With thousands of GO's, Update will be called thousands of times per game update there is no getting away from that.
     
  5. dterbeest

    dterbeest

    Joined:
    Mar 23, 2012
    Posts:
    389
    It's up to you. Basically the CreateTimer function looks like this:
    Code (csharp):
    1.  
    2. public Timer CreateTimer() {
    3.   Timer result;
    4.   if (_timerPool.Count > 0) {
    5.     result = _timerPool[0];
    6.     _timerPool.Remove(0);
    7.   } else {
    8.     GameObject go = GameObject.FindWithTag("timerObject");
    9.     result = go.AddComponent<Timer>();
    10.   }
    11.   return result;  
    12. }
    13.  
    Also, to make the story complete. A timer can be held on to by an object (if it wants), or object can call GameManager.Instance.ReleaseTimer(myTimer);
    The timer will then be put back in the timerPool for later use
     
  6. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,261
    Thank you for the clarification, pooling the timers is a must. Thank you for the example, helps a lot.
     
  7. Steamc0re

    Steamc0re

    Joined:
    Nov 24, 2014
    Posts:
    144
    So I can create a coroutine in a script on each GO that needs it using the coroutine example above with no retained computation overhead when the coroutine is yielded?
     
  8. Steamc0re

    Steamc0re

    Joined:
    Nov 24, 2014
    Posts:
    144
    Wow the coroutines method is so awesomely easy. Thanks for the help al.