Did you know that your potential customers have different PCs? Oh, you knew that already? Well, then maybe you have thought that your game will run at different frame rates on their PCs. How and why should this trouble you? Start WED, open the work19 level file, build it and run it using the script19 file:
The car is rotating all the time; I bet it changes its pan angle in a while loop! Let's check the script19 file in SED:
See? It does that indeed! It is good to see such a short script from time to time, isn't it?
Take a look at function main; the first line of code limits the frame rate to 30 frames per second. But what would happen if I would set fps_max to 500? Let's do the change right now:
Run the script file again and you will notice that the car rotates much faster this time. Press the Tab key on your keyboard to bring up an old friend (the console) and then type the following line of code and press Enter:
fps_max = 10;
The rotation is really choppy now and the rotation speed has decreased a lot! The car used to make a full rotation in about 5 seconds at 30 fps, and now it needs 16 seconds for a full rotation! Please understand that some (if not most) of your customers will have old PCs and the frame rate will be smaller on their systems. And don't forget that their money have the same color! How can we please them all?
Here's the golden rule: your game must run great on new PCs and it must run as good as possible on older PCs. Conitec has done a great job with the Acknex engine, making sure that it will run on any decent 3D card available on the market. Let's see what YOU can do about that:
- You can bundle your game with the hottest 3D card available on the market. If you sell many copies of your game, the 3D card supplier might give you a big discount :)
- You have to program your game wisely, making sure that it will run at the same speed (not at the same frame rate!) on the PC listed as "Minimum hardware requirements" on the game box, as well as on the newest PC that will be available in 2010.
Let's get back to our example. The frame rate will be bigger or smaller depending on the configuration of the PC and there's nothing you can do about that; however, you should make sure that the car from our demo makes a full rotation in 5 seconds even if the frame rate ranges from 10 to 1000 fps.
One of the methods I've used in the previous workshops was to set fps_max to a small value. This technique was heavily used in the older games, but today it isn't considered to be good enough; your game must run at the highest possible frame rate on high end PCs (that's why they've paid more money!) and at a decent frame rate on weak PCs, so you shouldn't lock the frame rate.
If I set fps_max to 30 and my customers have new PCs, I treat them as if they were customers with ancient PCs, not to mention that the problem isn't solved for the guys with PCs that can deliver only 10 fps. I have told you that fps_max only sets the upper limit for the frame rate; there isn't any magical instruction to double or triple a small frame rate.
On a side note, the frame rate depends only on the CPU and the video card; adding much more memory or a bigger hard drive won't increase the number of frames per second.
Well, now that you know all there is to know about the problem, let's see the solution! You will have to edit a single line of code in your script19 file:
Save the script and run the level again; you will notice that the car makes a full rotation arbout its pan angle in about 5 seconds, just like before. Now press Tab to show the console and set the frame rate limit to 10 fps:
fps_max = 10;
Surprise! The movement is choppy, but the car makes the full rotation in... 5 seconds! This time the frame rate didn't have any impact on the rotation speed! Try to set several different values for fps_max (10...100) and you will notice that the rotation speed is almost independent on the frame rate. Now what is it with that mysterious time_step and how does it work?
The new variable - time_step - gives us the duration of the last frame in ticks (1/16 second units) which translated to English gives us the following formula:
time_step = 16 / fps
This means that time_step == 1 when the frame rate is 16 fps, time_step == 0.5 when the frame rate is twice that value (32 fps) and so on; notice how time_step decreases its value as the frame rate increases. Let's pretend that we want to move an entity by increasing its x coordinate in a while loop:
action move_entity
{
while (1)
{
my.x += 1;
wait (1);
}
}
My PC is ancient and gets only 25 fps, while your new PC delivers 100 fps. This means that the while loop above runs 25 times a second on my computer and 100 times a second on your computer. In other words, my PC adds 25 quants (1 quant every frame) to the x coordinate of the entity every second, while your PC adds 100 quants (1 quant every frame) to the x coordinate of the entity every second. Take a look at the picture below to see the distances covered on both PCs over the same interval of 3 seconds:
Now let's add that miraculous time_step variable:
action move_entity
{
while (1)
{
my.x += 1 * time_step;
wait (1);
}
}
The loop continues to run 25 times a second on my PC and 100 times a second on your PC; we can't change that. However, the distance covered each frame will depend on the frame rate now. Let's do some simple math calculations:
time_step = 16 / 25 fps = 0.64 on my PC
time_step = 16 / 100 fps = 0.16 on your PC.
This means that the entity in the while loop above will cover a distance of 25 frames * 1 * time_step = 25 * 1 * 0.64 = 16 quants a second on my PC and 100 frames * 1 * time_step = 100 * 1 * 0.16 = 16 quants a second on your PC! The entity will cover the same distance on any PC, no matter how big or small is its frame rate.
Important tip: In previous engine versions this variable had a different name: time. So when you read scripts by other people who multiply something by time, you know that time_step is meant.
How do we use time_step in our projects? Maybe you've learned in school physics that distance is speed multiplied by time. So we just multiply all our speeds and angular speeds (the right side of the expressions or the figures that appear in our expressions) with time_step to get our resulting distances and angles. That's it! Here are a few examples:
my.z += 2; should be changed to my.z += 2 * time_step;
my.roll += 1; should be changed to my.roll += 1 * time_step;
c_move (my, nullvector, vector(5, 0, 2), GLIDE); should be changed to c_move (my, nullvector, vector(5 * time_step, 0, 2 * time_step), GLIDE);
It doesn't make too much sense to multiply zero with time_step because the result will always be the same: zero.
There are few more parameters that can change the value given by time_step (like time_factor, time_smooth, fps_min) but you will learn about them in the reference manual. Don't worry if you are feeling a bit disoriented: we are going to use time_step in all the following workshops, so you'll become a Time Master in no time!