Timers can suck it

Posted by aBethke on Tuesday May 4, 2010 Under Bag o' Tricks, Game Development

Salvidor Dali PaintingI think the title of this post really sums up my entire sentiment as far as the Timer class goes in Flash. Many people have recently heard me speaking, arguably ranting, on the subject so I thought I would quickly highlight a few reasons to avoid using Timer, the one place that I have found that I had to use Timer and offer an alternative piece of code to use in the majority of cases where a timer like mechanism is needed.

Why Timers Suck

Inconsistent Behaviour
The Timer class does not perform the same when running on a Mac vs a PC. The behaviour, for whatever reason, seems to get unreliable on a MAC and ultimately causes a lot of issues, especially in games.

Memory Leaks / Garbage Collection
AS3 has proven to be a fun place for memory management related issues due to how the latest Garbage Collector works. In this case Timers, when not carefully managed, can cause memory leaks due to the fact that an object instance will not be garbage collected when a timer is active on it. AS3, not for lazy developers anymore.

Performance Lag vs Accurate Timing
This comment is subjective and based on my personal experience but I’ve found with timing related issues and the performance challenges that can come into play with larger projects in Flash that an Event.ENTER_FRAME based timer is better than an actual Timer. The reason is when you have a program lag out and the FPS starts to take a nose dive, if you are using a Timer the mechanism is still active and firing independent of the application lag. Alternatively, if you are using a frame based timer/counter mechanism then the timer will lag out with the rest of the application and the overall timing will still fire in the sequence it was programmed to, all though it will obviously be slow due to performance lag.

I am shamed” aka The one time timers won

Over the last 7 years of working with Actionscript there was only one place where I absolutely found it necessary to use a Timer rather than a frame based counter. When I was working at Cryptologic we ran into an issue relating to sounds being played on Vista where the sound device was broken or someone had unplugged their headset/speakers after the game had started. For a number of quirky reasons Flash wasn’t handling these situations well and we had to devise a system to address the problems we were encountering. Long story short, I ended up using a Timer in conjunction with the sound management system I had built to accurately track the playback time of each sound clip. In this one case the timing of the frame counter was not accurate enough and I had to use a Timer.

Forget Timers, use this!

With the ranting about timers aside I will now offer up an alternative implementation that will take care of basically all of your timer needs. This class, FrameTimer, uses the Event.ENTER_FRAME / counter method I have mentioned and dispatches a completion event once the timer duration has expired. It can be used in a similar manner to a Timer implementation while addressing all the issues I mentioned above to which Timers fall victim.  Take it, use it, love it… or not. XP

FrameTimer.as
[cc lang=”actionscript3″ line_numbers=”true” no_links=”true” width=”100%”]
package com.goldengear.utils
{
import flash.display.Sprite;
import flash.events.Event;
/**
* FrameTimer.as was developed as a more stable alternative to flash.utils.Timer.
*
* @author Golden Gear
*/
[Event(name=”frameTimerComplete”, type=”com.goldengear.utils.FrameTimer”)]

public class FrameTimer extends Sprite
{
/**
* Constructor. Inits the enter handler for Event.ENTER_FRAME and stores the time duration.
*
* @param in_time The timer duration in number of frames.
*/
public function FrameTimer(in_time:int)
{
m_time = in_time
addEventListener(Event.ENTER_FRAME, handleEnterFrame, false, 0, true)
}
/**
* Destructor. Cleans up the timer instance once it has expired.
*/
public function destroy():void
{
removeEventListener(Event.ENTER_FRAME, handleEnterFrame)
if (parent != null)
{
parent.removeChild(this)
}
}
/**
* Event.ENTER_FRAME handler the is the core of the timer mechanism. Checks the timer duration and destroys itself/dispatches a completion event when done.
*
* @param in_event The triggering event.
*/
protected function handleEnterFrame(in_event:Event):void
{
m_time–
if (m_time <= 0)
{
destroy()
dispatchEvent(new Event(TIMER_COMPLETE, true, true))
}
}
/**
* @private
* The timer duration.
*/
protected var m_time:int = 0
/**
* The completion event dispatched by this class.
*/
static public const TIMER_COMPLETE:String = “frameTimerComplete”
}
}
[/cc]

Comments are closed.