Best practices: ENTER_FRAME vs. Timer

actionscript-3

I'm creating a Flash game which is based on the old Pacman and I'm not sure which is the best way to control the animation.

As I understand it these type of games were originally dependent on a game loop which ran faster or slower depending on the CPU, which is why I imagine that the most similar to use would be the ENTER_FRAME event.

This however presents the problem of having to have a specific frame rate and changing it later is out of the question, not to mention being limited to very few different "speeds" (see below). An example could be that the sprite has to move 12 pixels before the next move is determined. If the speed is then 4 pixels per frame, the math is quite simple:

[...]
public var stepCount:uint = 0;

[...]

function enterFrameHandler(e:Event):void
{
    if(stepCount==0) {
    //Some code to evaluate next move. Let's say it evaluates to MOVE RIGHT
    }

    if(MOVE_RIGHT)
    {
        x += 4;
    }

    stepCount++;
    if(stepCount > 2)
    {
        stepCount = 0; //Now ready to evaluate direction again.
    }
}

This all works fine, but let's say that I want the sprite to move 5 pixels per frame. Then the number of frames before making the next evaluation would not compute. The stepSize would have to be a multiple of 12, which limits the different possible speeds (1,2,3,4 and 6 pixels per frame).

This is why I attempted to base the movement on a Timer instead, which I also managed to get to work, but the movement was somewhat erratic and it seemed like the Timer was using far more memory than the ENTER_FRAME event. Instead of an even movement the Timer made the sprite slow down and speed up and slow down again.

Another possible solution could be the Tween class, but it seems extravagant.

Does anyone have experience with what works best in other games?

Morten Twellmann

Best Solution

You have several separate issues here. Your first question is, should you execute your game loop in a frame event or a timer event? The answer is easy - you should do it in a frame event. The reason is that regardless of how you move your characters, the screen is updated precisely once per frame. So any time you're calling your game loop more than once per frame you're wasting CPU, and any time you call it less than once per frame, you're sacrificing visual quality. So this one is easy, don't bother with timer events at all.

The next question is whether your game's movement should be tied to frames or miliseconds, and the answer is that it depends on the game. Ask yourself this: suppose that some user is playing your game, and their spaceship (or whatever) is flying along at a given speed. Suddenly, the user's anti-virus package does something heavy, and the CPU spike causes Flash to stop updating for one second. Once the spike is over, do you want the spaceship to continue moving from where it was when the spike started? Or do you want it to jump forwards to where it would be if it had continued moving during the spike? If you want the former, you should tie your movement to frames; if you want the latter, you should tie it to miliseconds. But which one is best depends on how you want your game to work.

The final question is, how exactly should you move the characters in your game? Based on what you wrote, I'd do it as follows. For frame-based movement (i.e. the first approach described earlier):

// the ship moves 25 pixels per second
var shipSpeed:Number = 25;

// the number of seconds per frame, based on the published framerate
var frameTime:Number = 1 / stage.frameRate;

// game loop called each frame:
function gameLoop() { 
    // ...
    playerShip.x += shipSpeed * frameTime;
    // ....
}

This way, the ship's movement on screen is constant, regardless of what framerate you publish your SWF at. Using a higher framerate simply makes the movement smoother. Likewise, to tie your movement to time instead of frames, simply change "frameTime" in the code above to refer to the time elapsed since the previous frame, as described in Allan's answer.

Related Question