Timer System
Sample snippets and explanations of methods and fields used in Timer System.
|
#Key ConceptsLearn about the details of the Timer System such as the event types available and how the properties and methods interact together
|
#Fields And MethodsLearn about the different fields, properties, and methods of the Timer System
|
#ExamplesSee some examples of the Timer System being used in a variety of ways, demonstrating the simplicity and power of it
|
Key Concepts
- Timer Cycle: Throughout this documentation you may see the term "per cycle" or "previous cycle". That refers to the full duration of a timer. A timer that repeats every 3 seconds has one cycle every 3 seconds. Updates happen on the timer no matter how long or short a cycle is and always happen each frame that the timer is active.
- Action Types
- Created: Triggers just after creation of the timer.
- Expire: Triggers on the frame where the timer's elapsed time exceeds the duration of the timer.
- Reset: Triggers when the timer is reset, either manually or automatically.
- Update: Triggers every frame that the timer is updated.
- Destroy: Triggers when the timer is destroyed.
- Overflow Time: This is the time that a timer overshoots the duration. For example, if there is a timer that expires after 1 second (1,000 milliseconds), the timer is at 0.995 seconds (995 milliseconds), and your game is running at 60 frames per second (0.01667 seconds [16.667ms] between frames) then the next frame, your timer will be at 1.01167 (or just under 1,012 milliseconds). It will trigger the expire event at this stage. However, if the timer were to just reset back to 1 second, you would lose that tiny fraction of time (~12 milliseconds). If this happens every cycle then it only takes a few cycles to become noticeably behind -- especially on quicker timers! By "wrapping" or accounting for overflow time, this problem is mitigated to keep the timer running closer to real-time. How this works is by instead of setting the duration back to 1 second directly, it adds the duration back into the elapsed time. Meaning in the above example, the new duration wouldn't be 1 second, it would be 0.988 seconds (or 988 milliseconds, accounting for the missing 12ms from the previous cycle.)
- Dynamic Timers: These timers are special timers that actually wrap a Unity Coroutine behind the scenes. The main purpose of these timers is to allow a custom frame rate for updates. This comes in handy when you have some CPU intensive code that needs to run occasionally and comes with the benefit of being able to update the frame rate on the fly if needed. For example, let's say you are building a Tower Defense game. If you have 100 enemies and 12 towers, checking if they are all in range can be an expensive operation. Instead of checking every enemy on every tower every frame (at 60 fps, that would be 7200 range checks per second!) you could check every tower every 1 second. If any enemy is found to be in range, you could then increase the resolution to be 10 checks per second and still have a responsive game while using only 1/6 of the checking as the worst case scenario. Less unnecessary checking means more enemies or towers can be present in your game!
Fields, Properties, and Methods
- ID (string): The GUID (as a string) of the ID for this timer. The TimerSystem class can take an ID in most of its methods to find the timer itself if it isn't available to pass in.
- Duration (float): The time in seconds of the full duration of the timer.
- Delta (float): The time in seconds that the timer has elapsed this cycle.
- IsExpired (bool): Boolean that returns true if Delta >= Duration, false otherwise.
- Active (bool): Boolean that returns if the timer is active and currently updating or not.
- AutoReset (bool): Boolean that determines how the timer reacts when it expires. If this value is true, the timer will automatically reset and start the next iteration. If this value is false, the timer will deactivate itself
- WrapOverflowTime (bool): Boolean that returns if the timer compensates for overflow time on an AutoReset. If this is true, it adds Duration to Delta. Otherwise, it just sets it to Duration. OverflowTime is discussed below in more detail.
- UpdateSource (TimerUpdateSource): Determines how the timer gets the delta value for each frame. The TimerUpdateSource enum is discussed in detail below.
- Actions (Dictionary<int, List<EventTimer_EventObject>>): Contains the actions that are associated with this timer. The dictionary is setup to have a key of an int conversion from the EventStages enum to a list of EventTimer_EventObject objects. This model allows multiple actions to be associated to each stage.
Examples
If the expire event is the only one needed and you aren't going to have the timer repeat, there is a simple wrapper that makes the timer behind the scenes. It still returns the EventTimer object if you need to adjust other fields on the timer or want to reference it later:
Delayed Event
If you do want to have a repeating timer, you can do so by using the normal flow to create a full event timer as seen below. As with all EventTimers, you can have it not repeat by setting the autoReset field to false. It is true by default.
Repeating Expire Event
Dynamic Resolution Timers allow you a quick way to instantly reduce (or increase) how often updates are run. No more creating coroutines yourself with annoying date time calculations or calculating out WaitForSeconds durations!
Dynamic Resolution Timer
Here is a full Event Timer that features all of the possible events used. It will trigger OnCreated event first, then the OnUpdate event every frame for 5 seconds. After that the OnExpire event will trigger, following the OnReset event, and repeat that cycle, excluding the OnCreated event. OnDestroyed is setup, but never used as the timer is not destroyed.
Full Timer With Every Event
Below is an example to create a simple countdown timer. In addition, this snippet demonstrates using a method instead of anonymous functions. For this particular example, I chose to go with local functions. However, class methods are also acceptable assuming they are still in scope.
Countdown Example