When creating games (or, really, any sort of animation) using ActionScript, most developers rely on the ENTER_FRAME
event to synchronize their actions with when a frame is being rendered on the screen (effectively using it as their game loop). In any way you look at it, that’s the right way to do it, but it has some limitations of its own.
In the past, when I needed to control something using ENTER_FRAME
equivalents, I normally used a TickController class. The advantage of this class is that it allowed me to dispatch a “tick” event any number of times per second, skipping actual Flash frames as needed, or repeating tick calls per frame as necessary (something rarely recommended, I must add, but necessary under some conditions).
Recently, I started taking a different approach with a class I called GameTicker. This class was somewhat more flexible, in that it had its own control of time and allowed objects attached to it to be paused and resumed. It was heavily influenced by the way Unity works; it does things with somewhat of as rigid approach, as it could only use objects of a specific interface, requiring every kind of class to be especially prepared for it.
Over the past couple of weeks I’ve put together a different class that, in my opinion, solves both problems in a much more elegant fashion. It’s called GameLooper and it’s available on GitHub. It’s used like so:
// Create GameLooper instance and start it var looper:GameLooper = new GameLooper(); // Add a signal callback, using a Signals-like approach looper.onTicked.add(onTick); // Actual callback function private function onTick(currentTimeSeconds:Number, tickDeltaTimeSeconds:Number, currentTick:int):void { var speed:Number = 10; // Speed of the box, in pixels per seconds box.x += speed * tickDeltaTimeSeconds; // Easy, accurate calculation }
At the very basic level, GameLooper doesn’t do anything more than what ENTER_FRAME
already does (and, obviously enough, that’s the event it uses internally). Its advantages, however, are:
- GameLooper keeps track of relative time and ticks passed via
currentTimeSeconds
,tickDeltaTimeSeconds
, andcurrentTick
. This is not just agetTimer()
call; time can actually be manipulated internally and the GameLooper instance can be paused, resumed, and have itstimeScale
changed. - The “tick” event call is flexible: by specifying
minFPS
ormaxFPS
parameters when creating the GameLooper class, it can be dispatched more than once per Flash frame (if you absolutely need something checked a number of times per second), or skip frames as needed (if something only needs to be executed a few times per second).
Previously, in games, I’d either use the old GameTicker, or create my World instances with its own ENTER_FRAME
engine and time calculation. By offloading the responsibility of dispatching the tick event and controlling time to an auxiliary class, I think it makes development of World-controlling classes much simpler and more flexible, with no discernible trade-off.
One thing I have started realizing recently – especially when creating games for Ludum Dare – is that I tend to spend too much time obsessing over creating subsystems and refactoring them until I’m happy, often forgetting to create a cool, fun game around it. That is to say, while this new GameLooper class is a result of things I have actually created at work, it’s also part of preparation for the next Ludum Dare (#27), which has just been announced (it will take place in August 23-26th; and theme suggestions are now open). My plan right now is to create something for the OUYA and its controller using Adobe AIR (and its new GameInput APIs), hence why I’m getting some kind of generic framework ready for it before it starts. We’ll see where it goes.
That looks handy. Very signals-like syntax.
I also have this problem of reviewing my code instead of just release things. I think I’m getting better at this with the time but still is something that bothers me.