Unity Timer
Run actions after a delay in Unity3D.
This library has been battle-tested and hardened throughout numerous projects, including the award-winning Pitfall Planet.
Written by Alexander Biggs + Adam Robinson-Yu.
Fork by GH-ZJ(wustzhangjie@gmail.com)
Basic Example
The Unity Timer package provides the following method for creating timers:
public static DelayTimer DelayAction(float duration, Action onComplete, Action<float> onUpdate = null, bool useRealTime = false, MonoBehaviour autoDestroyOwner = null);
public static DelayFrameTimer DelayFrameAction(int frame, Action onComplete, Action<float> onUpdate = null, MonoBehaviour autoDestroyOwner = null);
public static LoopTimer LoopAction(float interval, Action onComplete, Action<float> onUpdate = null,bool useRealTime = false, bool executeOnStart = false, MonoBehaviour autoDestroyOwner = null);
public static LoopTimer LoopAction(float interval, int count, Action onComplete, Action<float> onUpdate = null, Action onFinished = null, bool useRealTime = false, bool executeOnStart = false, MonoBehaviour autoDestroyOwner = null);
public static DelayTimer PersistenceDelayAction(float duration, Action onComplete, Action<float> onUpdate = null, bool useRealTime = false, MonoBehaviour autoDestroyOwner = null);
public static DelayFrameTimer PersistenceDelayFrameAction(int frame, Action onComplete, Action<float> onUpdate = null, MonoBehaviour autoDestroyOwner = null);
public static LoopTimer PersistenceLoopAction(float interval, Action onComplete, Action<float> onUpdate = null,bool useRealTime = false, bool executeOnStart = false, MonoBehaviour autoDestroyOwner = null);
public static LoopTimer PersistenceLoopAction(float interval, int count, Action onComplete, Action<float> onUpdate = null, Action onFinished = null, bool useRealTime = false, bool executeOnStart = false, MonoBehaviour autoDestroyOwner = null);Motivation
Out of the box, without this library, there are two main ways of handling timers in Unity:
- Use a coroutine with the WaitForSeconds method.
- Store the time that your timer started in a private variable (e.g.
startTime = Time.time), then check in an Update call ifTime.time - startTime >= timerDuration.
The first method is verbose, forcing you to refactor your code to use IEnumerator functions. Furthermore, it necessitates having access to a MonoBehaviour instance to start the coroutine, meaning that solution will not work in non-MonoBehaviour classes. Finally, there is no way to prevent WaitForSeconds from being affected by changes to the time scale.
The second method is error-prone, and hides away the actual game logic that you are trying to express.
This library alleviates both of these concerns, making it easy to add an easy-to-read, expressive timer to any class in your Unity project.
Features
- Make a timer repeat by call Timer.LoopAction.
private void Start()
{
Timer.LoopAction(5, () => { Debug.LogError("Timer Called"); });
}- Make a loop timer execute when start by setting
executeOnStartto true.
private void Start()
{
Timer.LoopAction(5, () => { Debug.LogError("Timer Called"); }, executeOnStart: true);
}- Make a timer based on frame count by call Timer.DelayFrameAction.
private void Start()
{
Timer.DelayFrameAction(5, () => { Debug.LogError("Timer Called"); });
}- Measure time by realtimeSinceStartup instead of scaled game time by setting
useRealTimeto true.
private void Start()
{
Timer.DelayAction(5, () => { Debug.LogError("Timer Called"); }, useRealTime: true);
}- Cancel a timer after calling it.
Timer timer;
void Start() {
timer = Timer.LoopAction(5, () => { Debug.LogError("Timer Called"); });
}
void Update() {
if (Input.GetKeyDown(KeyCode.X)) {
Timer.Cancel(timer);
}
}- Attach the timer to a MonoBehaviour by setting
autoDestroyOwnerto the MonoBehaviour, so that the timer is destroyed when the MonoBehaviour is.
Very often, a timer called from a MonoBehaviour will manipulate that behaviour's state. Thus, it is common practice to cancel the timer in the OnDestroy method of the MonoBehaviour. We've added a convenient extension method that attaches a Timer to a MonoBehaviour such that it will automatically cancel the timer when the MonoBehaviour is detected as null.
public class CoolMonoBehaviour : MonoBehaviour {
private void Start()
{
//The timer will cancel when the MonoBehaviour is destroyed;
Timer.DelayAction(5, () => { Debug.LogError("Timer Called"); }, useRealTime: true, autoDestroyOwner: this);
}
private void Update()
{
// This code could destroy the object at any time!
if (Input.GetKeyDown(KeyCode.X)) {
GameObject.Destroy(this.gameObject);
}
}
}- Update a value gradually over time using the
onUpdatecallback.
// Change a color from white to red over the course of five seconds.
Color color = Color.white;
float transitionDuration = 5f;
Timer.DelayAction(transitionDuration,
onUpdate: secondsElapsed => color.r = 255 * (secondsElapsed / transitionDuration),
onComplete: () => Debug.Log("Color is now red"));- A number of other useful features are included!
timer.Pause()timer.Resume()timer.Cancel()timer.Restart()timer.GetTimeElapsed()timer.GetTimeRemaining()timer.GetRatioComplete()timer.isDoneTimer.CancelAllRegisteredTimers()Timer.PauseAllRegisteredTimers()Timer.ResumeAllRegisteredTimers()
- Make a timer not effect by
Timer.XXXAllRegisteredTimers()function by callTimer.PersistenceXXX()function.
Timer timer;
void Start() {
//The timer will not cancel when Timer.XXXAllRegisteredTimers();
timer = Timer.PersistenceLoopAction(5, () => { Debug.LogError("Timer Called"); });
}
void Update() {
//No effect to timer
if (Input.GetKeyDown(KeyCode.X))
Timer.CancelAllRegisteredTimers();
//Only this can cancel persistence timer
if(Input.GetKeyDown(KeyCode.C))
Timer.Cancel(timer);//same to timer?.Cancel();
}- All timer creater functions can shortcut call by using Monobehavior Extensions functions, and the timer will attach to the Monobehavior so that the timer is destroyed when the MonoBehaviour is.
void Start() {
//The timer will attach to the MonoBehaviour instance.
this.DelayAction(5, () => { Debug.LogError("Timer Called"); });
}- A test scene + script demoing all the features is included with the package in the
/Examplefolder.
Usage Notes / Caveats
- All timers will not destroy when change scene, because TimerManager is
DontDestroyOnLoad.