First of all, this is how you typically do movement:
Code: Select all
repeat playerx = playerx + 1 playery = playery + 1 DisplayFrame(1, playerx, playery, 1) until stop=1
If you for example have ever tried playing old Sierra games like Kings Quest 1, 2, 3, Police Quest 1, Leisure Suit Larry 1, Space Quest 1, 2 or 3 and you choose the speed as "Fastest", you will notice something.
Use Amiga 500 and the speed is quite nice as fastest. Use Turbocarded Amiga, And you cant control that guy anymore since it moves too fast.
This is what happens with this example too. It might be working nice and fine with your machine, but put it to slower or faster machine, and its either painstakingly slow, or simply too fast to play.
There are two solutions to this: easier, and better but bit more complex solution.
First the easier solution:
Code: Select all
repeat StartTimer(1) playerx = playerx + 1 playery = playery + 1 DisplayFrame(1, playerx, playery, 1) WaitTimer(1, 40) StopTimer(1) until stop=1
Timer works following way. when you choose StartTimer(1), it will start timer number 1, this is like having one of those watches that you can use for timing. The number tells which one of the watches to start.
So if you have StartTimer(1), StartTimer(2) and StartTimer(3), it is like starting 3 different wrist watches to measure the time passed. And just like wrist watches, you can also stop these independently, that you can choose to StopTimer(2), while Timer 1 and 3 still continue going.
So StartTimer(number) starts the counting and StopTimer(number) stops it.
When Using WaitTimer(number, another number) command, it will tell program to halt until certain time have reached.
It works so that first number is the Timer (wrist watch) which to use, and second number tells to what point we want to use it for.
Command WaitTimer(2, 40) would with Wrist watch logic mean that program would wait until Wrist watch number 2 have reached 40 seconds, and after that continue forward.
In real version, time however is not seconds.
In Timer the time goes so that every 1 000 units is one second.
So if I want to wait for say 5 seoncds before continuing, i would use:
This would equal of waiting for Timer 1 to have been going for 5 seconds.
In the example program I used WaitTimer(1, 40). This means that code would be executed 25 times per second.
Good thing about this is, that no matter how fast machine you have, it would always wait until that certain time is reached before executing the next repeat and hence game plays same speed on any machine basically.
However, theres a draw back on this. First of all. If you have a fast machine, you get no benefit from it, since it still keeps refreshing the screen the same speed as well, and bigger draw back is that if ou have a game something like Dune II, it might happen that there comes so much stuff on screen at once, that slower machines wont be able to handle all the things in that 25th of a second time, and since this one forces you to go through every loop, it could become extremely slow and painful process to play it.
Hence there is the most times best solution although bit more complex:
Code: Select all
repeat StartTimer(1) playerx = playerx + ( (1/1000) * timepassed ) playery = playery + ( (1/1000) * timepassed ) DisplayFrame(1, playerx, playery, 1) timepassed = GetTimer(1) StopTimer(1) until stop=1
New command here is GetTimer(1)
It also requires you to use some variable with it, like the timepassed variable I am using.
Idea is that by using the wristwatch analogy again this command means that we are going to watch the time that is on wristwatches display at that exact time and mark it up to that variable timepassed.
This makes it possible to have the game run at same speed on any machine regardless wether there comes lot of stuff to screen or not.
For fierst we store the timepassed value, which could be for example 20 (1/50th of a second)
We have now decided that playerx speed should be 1 pixel per second (extremely slow by the way)
Instead of using playerx = playerx + 1, we will now be using playerx = playerx + ( (1/1000) * timepassed)
Logic is folowing:
First we decide how fast we want player to move. In this example 1 pixel per second. For that reason we have to divide that speed by 1 000 (Timers one second)
After that we tell the program to move player forward that speed multiplied by timepassed.
Suppose we have very slow machine and it takes 2.5 seoncds for it to get to the loop again. that would mean that time had passed 2500 units.
Therefore it would move playerx 2.5 pixels forward.
Suppose we have very fast machine and it takes only 1/1000th of a secong. Then that means it would move playerx forward 0.001 pixel each loop, meaning that when moving one pixel, screen would be updated 1 000 times during that.
However, everything is not perfect yet.
For when you have a fast machine and not very heavy program, then it might happen that loop is executed faster than in 1 timeunit, in which case timepassed would result as 0, and hence everything would be moved multiplied by 0, meaning no movement at all.
Therefore we still need solution for this problem:
Code: Select all
repeat StartTimer(1) playerx = playerx + ( (1/1000) * timepassed ) playery = playery + ( (1/1000) * timepassed ) DisplayFrame(1, playerx, playery, 1) timepassed = GetTimer(1) If timepassed < 1 continueprogram=0 repeat timepassed = GetTimer(1) if timepassed => 1 then continueprogram=1 until continueprogram=1 endif StopTimer(1) until stop=1
Now we finally have a program that basically works on any machine at same speed (there are some small exceptions but this should be good enough for practically all).