Friday, August 30, 2013

Simple Timer in Unity3d

Standard
Hello All:

In our project we often need to run some function multiple time at a regular time interval. Unity does not come with any timer functionality. In this post I will explain how to make a simple timer.


First we will create Timer class which will be used to instantiate timer. This class will provide functionality to start and stop the timer.

public class Timer
{
    private GameObject timerGameObject;
    private TimerComponent timerComponent;
    /// <summary>
    /// Initializes the timer
    /// </summary>
    /// <param name="numberOfLoops">How many times to loop, pass 0 for infinite loops</param>
    /// <param name="runForSeconds">Each loop duraction</param>
    public Timer(int numberOfLoops = 5, float runForSeconds = 2.0f)
    {
        timerGameObject = new GameObject("Timer");
        timerComponent = timerGameObject.AddComponent<TimerComponent>();
        timerComponent.runForSeconds = runForSeconds;
        timerComponent.numberOfLoops = numberOfLoops;
        timerComponent.Listeners = new Dictionary<TimerListenerType, Action>();
    }
    public void Start()
    {
       timerComponent.Start();
    }

    public void Stop(bool isDestroy = false)
    {
        timerComponent.Stop();
        if (isDestroy)
        {
            Destroy();
        }
    }
    public void Destroy()
    {
        GameObject.Destroy(timerComponent);
    }

    public void AddListener(TimerListenerType listenerType, Action listener)
    {
        if (timerComponent.Listeners.ContainsKey(listenerType))
        {
           timerComponent.Listeners.Add(listenerType, listener);
        }
        else
        {
            timerComponent.Listeners[listenerType] = listener;
        }
    }
}
We will use following enum to pass listeners

public enum TimerListenerType
{
    Tick = 0,
    TimerComplete
}
Timer need a monobehavior to do the calculations needed for Time updates

public class TimerComponent : MonoBehaviour

{
    private float startTime;
    private float endTime;
    bool timerActive;
    public float runForSeconds;
    public int numberOfLoops;
    int currentLoopCount;
    public Dictionary<TimerListenerType, Action> Listeners;
    private bool isTimerComplete;
    void Update()
    {
        DoTimer();
    }

    public void DoTimer()
    {
        if (!timerActive)
            return;

        if (Time.time >= endTime)
        {
            if (numberOfLoops == 0 || currentLoopCount < numberOfLoops)
            {
                TriggerTick();
                currentLoopCount++;
                Active = true;
            }
            else
            {
                Active = false;
            }
            if (numberOfLoops != 0 && currentLoopCount == numberOfLoops && !isTimerComplete)
            {
                isTimerComplete = true;
                TriggerTimerComplete();
            }
        }
    }

    public bool Active
    {
        get { return timerActive; }
        set
        {
            timerActive = value;
            if (timerActive)
            {
                startTime = Time.time;
                endTime = startTime + runForSeconds;
            }
        }
    }
    public void Start()
    {
        currentLoopCount = 0;
        Active = true;
    }

    public void Stop()
    {
        Active = false;
    }

    public void TriggerTick()
    {
        CallOrThrow(TimerListenerType.Tick);
    }

    public void TriggerTimerComplete()
    {
        CallOrThrow(TimerListenerType.TimerComplete);
    }

    private void CallOrThrow(TimerListenerType type)
    {
        if (Listeners.ContainsKey(type))
        {
            Action action = Listeners[type];
            if (action != null)
            {
                action();
            }
        }
        else
        {
            switch (type)
            {
                case TimerListenerType.Tick:
                    throw new Exception("No listener for tick");
                case TimerListenerType.TimerComplete:
                    throw new Exception("No listener for timer complete");
                default:
                    break;
            }
        }
    }
}
Timer can be used in following way

   Timer timer = new Timer(2, 2);
   timer.AddListener(TimerListenerType.Tick, () => { Debug.Log("Timer tick called"); });
   timer.AddListener(TimerListenerType.TimerComplete, () => { Debug.Log("Timer complete called"); });
    timer.Start();


Hope this helps. Complete sample project can be downloaded here


Thanks for printing this post. Hope you liked it.
Keep visiting and sharing.
Thanks,
Ashwani.

0 comments :

Post a Comment