The Delay Factor

One of the major difficulties in game development is to make your game playable on as many computers as possible, and on as many newer (and possibly older) computers as possible. Games written today need to be programmed to run at the same speed on all PCs. If not, then your game may be unplayable for someone else, ruining their experience.

This is what I call the delay factor: a variable that changes relative to the speed of the computer, to which you base all your time-dependent functions on, such as movement and animation.

Perhaps you can remember playing an old game on a new PC, only to find that you can't play it because it runs too fast. Chances are they didn't program speed control into their game, or they used a hack-method that worked at the time but doesn't work today.

I will start off by telling you what NOT to do. I have made a lot of these mistakes before, and because of that I can't run many of my older games; I have to edit the source code to slow things down, or it's just too much work and I give up.

The WRONG Way

The worst thing you can do is something similar this:

DIM n AS INTEGER
FOR n = 0 TO 500000: NEXT n

This may solve the problem on your computer, and some speed control is better than no speed control. But if you want to share your game, or look back on it in the future, you need something better.

There are a number of ways to approach this issue. You could count how many times a loop runs within one second and use that as your delay factor, or you can make the loop count (500000) a variable and make the user adjust it him/herself. But these are poor methods and will likely frustrate other people, and they'll never truly know what speed you meant the game to be played at.

Another way is to utilize the vertical retrace. The vertical retrace waits for the monitor to refresh. Most monitors refresh at 60hz, or 60 times a second. So programming the speed of your game around this is a more viable option. Today, most computers will probably run your game, but some monitors refresh at 70hz or 75hz. In the future monitors may refresh at 120hz.

The RIGHT Way

The best solution, as far as I know, is to track how much time goes by between one cycle of your main game loop and use that time as the delay factor.

Of course with this way, the faster the computer, the shorter time and thus delay factor. So you can't throw the delay factor into a for loop unless you invert it, but a better way is described below.

Multiply all of your movements, animations, and other time-dependent objects by the delay factor. Don't code any stupid empty loops to slow things down. This way, if your game runs at a quadrillion cycles per second, the delay factor will compensate and everything will run at the same speed.

Another advantage of this method is that slower PCs will run your game also. If you're coding your game on a PC that runs it at 60fps, a PC that can only run it a 30fps will compensate by moving things twice as fast.

You still should test your game on both slower and faster computers as you're making it. Chances are you won't have everything running perfect the first time. Sometimes I make the mistake of slipping in an absolute value without multiplying it by the delay factor, and testing it on other computers is a way to catch that.

Use FreeBasic's TIMER command to do this. First you take the time before executing your game loop. Then once the cycle is complete, call TIMER again to get the new time. Subtract the old time from the new time to get the cycle time.

Example Code

I made a module below that you can use if you don't feel like coding your own.
Save this as DELAY.BAS. Include it in your game, then just call UpdateSpeed() after each cycle. It will return the time between the first time you called it and the second time. You can also call GetDelay() to get the delay factor again without recalculating it.

Keep in mind that you should call it at least once before your main game loop to initialize it. It will return the value of TIMER the first time it's called (which is usually a big number). A good way is to render a couple frames of your game first to get the speed before performing calculations that depend on the delay factor. The rendering process is usually the most processor intensive, so it'll give a fairly accurate time.


DECLARE FUNCTION UpdateSpeed () AS DOUBLE
DECLARE FUNCTION GetDelay () AS DOUBLE

DIM SHARED DelayDelay AS DOUBLE '- odd spelling as to not conflict with other variables in your code

'- Calculate the global delay factor
FUNCTION UpdateSpeed () AS DOUBLE

DIM speed AS DOUBLE
STATIC timex AS DOUBLE = 0.0f

speed = TIMER-timex
timex = TIMER

DelayDelay = speed

RETURN speed

END FUNCTION

'- Return the delay factor
FUNCTION GetDelay () AS DOUBLE

RETURN DelayDelay

END FUNCTION

No comments:

Post a Comment