Tutorial : Creating an Optimized AS3 Game Timer Loop

Tutorial : Creating an Optimized AS3 Game Timer Loop

It this tutorial we create what I consider to be my most optimized game timer loop. I will start with the game loop created in my last tutorial and optimize it further. We will add three different optimizations to the game loop. First, we will simply lock our canvas before we use the copyPixels operation on it. Then we will unlock it after. Second, we will implement a sleep based active render timer. Third, we will make sure our game loop updates on every event rather than on every frame.

One of the most discussed, least understood and ultimately most frustrating aspects of Flash game programming is keeping a constant frame rate across all of the different SWF players. We seem to get a different frame rate inside of the IDE, in the stand alone player, and in different browser / wmode combinations.

Normally, the theory is to keep your game running at about 30 FPS for smooth game play. So, what most of us do is set our Flash Movie frame rate at 30 FPS or more and hope for the best. If we are lucky enough to either create a game engine that doesn’t tax the Flash player, or are skilled enough to create an optimized engine, we will get a pretty constant frame rate in the Flash environment. When we export the game and try it in the external player, we might also get pretty close to 30 FPS. We are really happy, and then we try the game in a browser. Usually this is where the trouble starts In an IE browser with wmode set to the default (Window), we will usually see a 2-5 frame rate drop. If any other browser, especially Firefox, our frame rate can vary wildly downward from there. Now, the latest Firefox update might repair this, but there seems to always be a situation where the frame rate outside of the Flash IDE (and sometimes inside of it) will just not be what you expect.

One other common problem with game timer loops is the game engine taxing the processor in such a way that it causes the game to drop frames and at the same time drop update and render cycles. This results in a slowdown in game play because the rendering engine cannot keep up with demand. Nothing is going to keep a game playing smoothly on a very old machine, but within reason, we should be able to keep our game running pretty smoothly at our desired frame rate. How can we do this?

1. BitmapData.lock and BitmapData.unlock.
The simple theory behind locking a BitmapData object is to stop display objects that reference it from updating themselves (a very costly operation) when the BitmapData object is being rendered with multiple copyPixels operations. When unlock() is called, all of the changes are then reflected in the display object.
In practice, it would look like the following. We are going to take the game loop from my 7800 Asteroids game out of context here, but it is being used just for demonstration purposes.

1
2
3
4
5
6
7
8
9
10
11
12
    checkKeys();
    updatePlayer();
    updateRocks();
    updateMissiles();
    checkCollisions();
    canvasBD.lock();
    drawBackground();
    drawPlayer();
    drawRocks();
    drawMissiles();
    drawParts();
   canvasBD.unlock();

The above is a simple demonstration of the 7800 Asteroids game loop. Before any of the draw operations, we lock the canvasBD, which is our single display canvas for our game. All of the drawXXX() functions use copyPixel operations to BLIT to this canvas. By locking it, we stop the canvasBitmap display object (not in code above) from being updated until the canvasBD.unlock() is called. This helps to not use as much CPU during the copyPixel operations and is effectively a poor man’s doublebuffer operation without the double buffer overhead of having to copyPixels twice – once to the buffer and once to the display object.

2. The Sleep Based Timer using Active Rendering
The sleep based timer is definitely not my unique creation, and the code we will use isn’t even my implementation. A fellow Flash Game Head , and friend of mine, Chris Cutler, takes the credit for introducing me to this AS3 implementation of Andrew Davidson’s Java based version. Chris created the AS3 version based on Andrew’s excellent book, Killer Game Programming in Java. I don’t know Andrew, but his book is quite excellent and a great game development reference especially for AS3 programmers.

Andrew introduces a sleep based timer to actually slow down his code so it will run the same on all machines. In Flash we sometimes need to do this, but more regularly, we need to keep we struggle to keep our frame rate constant across platforms. He times the number of milliseconds it takes his game loop to run, and if he has time left over, he sleeps (or pauses) the loop until the next interation. This makes for a smooth loop. He adds to this technique to what he deems, Active Rendering. What he does is actually measure the time it takes to render the screen, and then make adjustments to his sleep timer based on these measurements. In this way, he has ultimate control over his game loop. By implementing this is AS3, so do we. Below is this code added to our game loop:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private function runGame(e:TimerEvent) {
    _beforeTime = getTimer();
    _overSleepTime = (_beforeTime - _afterTime) - _sleepTime;
   
    checkKeys();
    updatePlayer();
    updateRocks();
    updateMissiles();
    checkCollisions();
    canvasBD.lock();
    drawBackground();
    drawPlayer();
    drawRocks();
    drawMissiles();
    drawParts();
    canvasBD.unlock();
   
   _afterTime = getTimer();
    _timeDiff = _afterTime - _beforeTime;
    _sleepTime = (_period - _timeDiff) - _overSleepTime;        
    if (_sleepTime <= 0) {
        _excess -= _sleepTime
        _sleepTime = 2;
    }        
    gameTimer.reset();
    gameTimer.delay = _sleepTime;
    gameTimer.start();

    while (_excess > _period) {
        checkKeys();
        updatePlayer();
        updateRocks();
        updateMissiles();
        checkCollisions();
        _excess -= _period;
    }
   
    frameTimer.countFrames();
    frameTimer.render();
    if (aRock.length ==0 && aActiveParticle.length==0) stopRunningGame();
   
}

In our Variable Definition Section, we have added these variables:

1
2
3
4
5
6
7
8
    public static const FRAME_RATE:int = 40;
    private var _period:Number = 1000 / FRAME_RATE;
    private var _beforeTime:int = 0;
    private var _afterTime:int = 0;
    private var _timeDiff:int = 0;
    private var _sleepTime:int = 0;
    private var _overSleepTime:int = 0;
    private var _excess:int = 0;

FRAME_RATE is set to be the number of updates we want per second. I like 40, so I have set mine to that.

_period is the number of milliseconds that we have to perform all of the operations per period.
In this case it is 25 (1000/40)

_beforeTime and _afterTime will create a simple code profiler.
We time all of the operations in our loop and see how long it too in milliseconds..
We hope for it to take less than 25 milliseconds (or _period value).

_timeDiff is the difference between the _afterTime and the _beforeTime.

_sleepTime is the period (25) minus the _timeDiff.
From both of these we subtract our _overSleepTime.

_overSleepTime is a measure of how accurate or sleepTime is on the last interval.
If the sleep time was off by a couple milliseconds, they will be added to the overSleep
for the next interval.

_excess holds all of the excess time that occurs in the render loop.
It is a running total in a way and it keeps the whole loop honest.
When the _excess is greater than our period (25) then we do an extra checkeys(), update(), and check collisions() of our objects.
We don’t render them though.

What this code produces is a game loop that looks like it is rendering at the same speed even though in some cases the processor cannot keep up with the load. In that case, we update without rendering to keep objects moving at a constant rate. In the next render() the objects will appear at the new locations.

We have also mode a change to our gameTimer variable to make this work:

1
2
3
    gameTimer=new Timer(_period,1); //changed in part 3 from 50
    gameTimer.addEventListener(TimerEvent.TIMER, runGame);
    gameTimer.start();

Our gameTimer variable used to be created with just the number of milliseconds to update on each interval. This would make it run constantly until we called gameTimer.stop(). That’s not the case any more. We just run our gameTimer one time, then check the value produced (above) and the restart of loop after sleep is necessary. The number of milliseconds to repeat our interval is now to our _period (25), for this first one time run. We do this because our new method of timing will reset and start the timer inside the game loop – like this:

gameTimer.reset();
gameTimer.delay = _sleepTime;
gameTimer.start();

This starts up our gameTimer only after sleeping for the appropriate amount of time.

3. UpdateAfterEvent()
The third and final optimization we will add to this timer will be the use of the event.updateAfterEvent() method.
After taking a look at Keith Peter’s latest book on AS3, Actionscript 3.0 Animation (it should be on every Flash Game Developer’s book shelf, right next to the collective works of Colin Moock and Jobe Makar) I found this little tid bit.

By calling the event.updateAfterEvent() method of the TimerEvent object, we force Flash to update the screen immediately. In this way, we can set our movie Frame Rate to a relatively low number. I like 40. So, usually I would have set my FrameRate to 60 in hope that I would ge 35-40 in my browser. The result of this actually taxes the processor more because it is always trying to keep up with the 60 intervals per second. Now, with it set to 30, I can get the 40 updates a second I want and it will look smooth in all current browsers.

What do you do if the designer has created all of his animations set to 18 FPS, but the game needs to run at 30? Before now, I would have had to be very clever to handle this. Now, I can just set the movie to 18FPS and the FRAME_RATE (above) to 30. This will let you display animations at 18FPS, but game play can run at 30 updates a second.

Here is the game loop with this code added:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private function runGame(e:TimerEvent) {
    _beforeTime = getTimer();
    _overSleepTime = (_beforeTime - _afterTime) - _sleepTime;


    checkKeys();
    updatePlayer();
    updateRocks();
    updateMissiles();
    checkCollisions();
    canvasBD.lock();
    drawBackground();
    drawPlayer();
    drawRocks();
    drawMissiles();
    drawParts();
    canvasBD.unlock();
   
    _afterTime = getTimer();
    _timeDiff = _afterTime - _beforeTime;
    _sleepTime = (_period - _timeDiff) - _overSleepTime;        
    if (_sleepTime <= 0) {
        _excess -= _sleepTime
        _sleepTime = 2;
    }        
    gameTimer.reset();
    gameTimer.delay = _sleepTime;
    gameTimer.start();

    while (_excess > _period) {
        checkKeys();
        updatePlayer();
        updateRocks();
        updateMissiles();
        checkCollisions();
        _excess -= _period;
    }
   
    frameTimer.countFrames();
    frameTimer.render();
    if (aRock.length ==0 && aActiveParticle.length==0) stopRunningGame();
    e.updateAfterEvent();
}

Here is the 7800 Asteroids game Running with this new game loop code. This has a movie frame rate set to 30FPS, and in the IDE, external player and browser, it runs at a pretty constant 40-42 FPS.

 

Here is the 7800 Asteroids game Running with the older, non optimized game loop code. This has a movie frame rate set to 50 FPS, and the IDE, external player and browser, the frame rate wildly differs. The game loop is set to run every 15 milliseconds I can get 50-60 FPS in the external player and IDE (sometimes) but it drops to 30-35 when a lot of particles on the screen. In the browser (at least for me) it doesn’t get above 35FPS.

 

Here You can download the .fla and new class files for your own use.

0saves
This entry was posted in Tutorial-Flash, Tutorials. Bookmark the permalink.
  • Hong_en

    Thanks. I will try it when I wake up.

  • Swantje

    unfortunately since flash player 10.1 it doesnt looks smooth anymore…

  • mrbio

    Yes, with flash player 10 it is somehow lagging while still showing ~40 fps.
    Has anybody solved this ?

  • Antje

    Has anybody find a solution for the flash player 10.1 problem?

  • Krooked99

    Just came across this post while searching in google, i have the same problems with some games. They dont run smooth any and stuck sometimes. Would be great if anybody could explain that issue or even better has a soluten for that.

  • Jody

    i am still looking for a solution too. my games really sucks since flash player 10.1!

    • http://www.8bitrocket.com 8bitjeff

      When we were writing our Flash Games book we initially had every game working with this optimized sleep-based timer. Unfortunately last December we saw that the latest Flash players started to hiccup when “update after event” is turned on. If you want a simple solution, comment out the e.updateAfterEvent() in the loop. This will band-aid the problem but your game will work. The frame rate will become a little choppy though. At the 11th hour, as the book was about to be published we had to completely re-write everything to use standard timers (plus I add in a time-based step timer) in the last few games. I was livid that we had to do this and none of my emails were returned by Adobe on the subject. I tried everything I could think of to get this to work, but nothing replicated the e.updateAfterEvent() method of smoothing out the render. The time-based step timer does this in a different way and works, but it just isn’t the same.

      • Anonymous

        Any sign of improvement with Flash Player 10.2?

        I’m going to try out this game loop system and would be interested to see if the updateAfterEvent() situation had changed.

    • http://www.8bitrocket.com 8bitjeff

      When we were writing our Flash Games book we initially had every game working with this optimized sleep-based timer. Unfortunately last December we saw that the latest Flash players started to hiccup when “update after event” is turned on. If you want a simple solution, comment out the e.updateAfterEvent() in the loop. This will band-aid the problem but your game will work. The frame rate will become a little choppy though. At the 11th hour, as the book was about to be published we had to completely re-write everything to use standard timers (plus I add in a time-based step timer) in the last few games. I was livid that we had to do this and none of my emails were returned by Adobe on the subject. I tried everything I could think of to get this to work, but nothing replicated the e.updateAfterEvent() method of smoothing out the render. The time-based step timer does this in a different way and works, but it just isn’t the same.

  • Antje

    without the call updateAfterEvent() it looks the same.

  • ClaverFlav

    hey there, im a long time reader first time poster…

    i was recently experimenting with some different timer systems for individual units in this little flash game of mine. and i saw what everyone is talkin bout… some strange jittery motion on my objects (just boxes on a single color background [no blitting yet]) but during my experimentation i discovered a weird … technique.

    so i got a document class that drives my main game loop timer… i got “new timer(5)” and that timer event triggers the “e.updateAfterEvent”. additionally i put “this.stage.frameRate=10;” in the constructor. which combines to make 100 fps i think

    so then rather than have this document class go through and update each unit and then draw, i got three different unit classes managing themselves. one with a time sytem built around enterframe, another with a deltatime system combined with enterframe, and finally for just a weird test a class with a timer of 1 ms(additionally calculating deltatime). each one of these classes ‘time system’ calls there own respective ‘tick’ functions that move them like so
    “x+=(5*dt); x=x%800;”

    the strange thing is the timer(1) class moves smooth as hell, while the others move like michael j fox… what gives?

  • http://twitter.com/Trent_Sterling Trent Sterling

    Excellent post on optimization. I’ve been working on my own frame rate independent system using time, and this is pretty much how I did things.

  • Pingback: FlashApplications » How to Optimize Flash Sprite Animations for Mobile

  • Pingback: Stable framerate in actionscript 3 games | Synerger Games

  • Anonymous

    I don’t know what happened since this article was posted but is it just me or is the lower of the two Flash running much smoother than the upper one?
    The little red Box at the top is showing constant 60 for the lower and 38-42 for the upper Version.
    Does this mean the old version of the game Timer is now the better solution?

    • Kevin S

      I think the point of this was optimized and stable frame rate. The lower of the two jumps around allot, while the top one is stable throughout the game.

      • Anonymous

        Does the lower really jump around? On my Computer it’s definitly not
        jumping more than the above and the Framerate of the lower is higher.
        The Movement on the lower is much smoother, as far as I can see.

  • http://www.web-hosting-service.in web hosting service

    Excellent post and now i am going to try this tutorial and i am very interested to see results.

  • http://www.dynamicinfoline.com web design bangalore

    very good tutorial , thanks for sharing.

  • Rajiv Thamburaj

    This has honestly reinvigorated my interest in AS3 programming; a great and flexible implementation that I’ll use in all of my future projects. Thanks!

  • http://stevenswood.com/ mendocino luxury hotels

    Keep up the brilliant inspirational concepts! It’s good to find that incredible post. Too much important aspects of PHP relevant input!