Timer Based Movements

Description

In many cases a game may run at the maximum frame rate possible on all platforms, usually 60 frames per second when vsync is on (it is on by default). This may well be the case for more simplistic games that aren't pushing the capabilities of the hardware too much. In other situations you may find that a game runs at different frames, for example, on Windows it may run at 60 frames per second, but on the iPhone at 30 frames per second. This will have the effect of the game running perfectly normal on Windows, but at half the speed on the iPhone, which is far from ideal. The way to counteract this problem is to introduce timer based movement into your game, which will result in your entities moving at the same speed regardless of the frame rate.

One approach to dealing with this problem is to calculate the time passed between frames / each cycle of the main loop and use this value as a multiplier that gets applied to any movement.

This example places a sprite on screen that is moved from the left over to the right. When it gets moved its new X location is calculated by applying a time based multiplier to it.

Getting started

The initial code for this example displays a background image and then creates another sprite that will later be moved on screen. The current time is also stored in the variable lastFrame:

SetVirtualResolution ( 320, 480 )

CreateSprite ( LoadImage ( "background7.jpg" ) )
LoadImage ( 1, "blue.png" ) CreateSprite ( 1, 1 ) SetSpritePosition ( 1, 0, 200 )
lastFrame# = Timer ( )

Calculating the multiplier

The process of calculating the difference between frames is fairly simple. At the beginning of the main loop the current time is stored, the difference is then calculated based on deducting the previous time from the current time, and finally the previous time is updated to the current time as shown here:

do
    thisFrame#  = Timer ( )
    difference# = thisFrame# - lastFrame#
    lastFrame#  = thisFrame#

Sync ( ) loop

The key data here is the difference between times, this needs to be saved and used in all movement based code.

Moving a sprite

Moving a sprite over to the right might typically look like this:

x# = GetSpriteX ( 1 )
x# = x# + 20
SetSpriteX ( 1, x# )

In order to ensure movement is handled by time a small alteration is needed:

x# = GetSpriteX ( 1 )
x# = x# + 20 * difference#
SetSpriteX ( 1, x# )

Notice how this time the movement is being multiplied by the time difference between frames, therefore the frame rate jumping up or down won't matter as our sprites movement takes into account these time differences. The end result is that this sprite will move across the screen at the same speed regardless of whether the game is running at 10 or 100 frames per second.

Full code listing

Everything is now in place. Here's the final code for our program. A few additional lines have been added so that the frame rate can be adjusted (for those platforms that support it). This adjustment will make the program run at half the speed, yet the sprite will continually move at the same speed:

SetVirtualResolution ( 320, 480 )

CreateSprite ( LoadImage ( "background7.jpg" ) )
LoadImage ( 1, "blue.png" ) CreateSprite ( 1, 1 ) SetSpritePosition ( 1, 0, 200 )
vsync = 1
lastFrame# = Timer ( ) do thisFrame# = Timer ( ) difference# = thisFrame# - lastFrame# lastFrame# = thisFrame#
x# = GetSpriteX ( 1 ) x# = x# + 20.0 * difference# SetSpriteX ( 1, x# )
Print ( "Touch or click the screen to turn" ) Print ( "Vsync on or off" ) Print ( "" ) Print ( "Vsync = " + str ( vsync ) ) Print ( "Frame rate = " + str ( screenFPS ( ) ) )
if GetPointerPressed ( ) = 1 if vsync = 1 SetSyncRate ( 30, 1 ) vsync = 0 else SetSyncRate ( 60, 1 ) vsync = 1 endif endif
Sync ( ) loop

Conclusion

This is a good start in understanding how to implement timer based movement. A more advanced solution might implement interpolation so that on slower platforms the movement would remain smooth, whereas with this example it would be somewhat jerky. It's also worth taking into account whether the extra overhead is necessary, as with some games it simply won't be an issue, but this is something that needs to be decided early on in the development otherwise you could end up running into issues changing styles later on.