I've written a crude program that creates and plays videos in qbasic (no sound yet). I wanted to adjust for the cpu speed, so I created a SUB to gauge the computer's speed. The code determines the maximum frames per second the cpu can handle, the number of empty FOR/NEXT loops the computer can run in one second for delay purposes, and a number that can be used to enforce a particular frame rate on the current cpu. (See comments for explanation in code below.)
The most relevant code to the asteroid game is the part that calculates the number of empty FOR/NEXT loops the cpu can cycle through in one second. Here's the essential steps for determining the magic number:
1. Cycle through a FOR/NEXT loop a certain number of times. (The larger the number of cycles, the more accurate the results.)
2. Get the current time. (Time1 = Time$)
3. Run the test. (FOR x = 0 TO cyclesToTest : NEXT)
4. Get the current time again. (Time2 = Time$)
5. Calculate the difference (in seconds) between the test's start and end times to find the total amount of time it took to run the test. (secsForTestRun = Time2 - Time1)
6. If it took the cpu more than a second to run the test, calculate the cycles per second by dividing the total number of FOR/NEXT loop cycles tested by the duration of the test in seconds. (cps = cyclesToTest / secsForTestRun)
(7. If it took the cpu less than a second to run the test, consider running the test for a much larger number of cycles.)
Since you don't want to pause the entire program while the delay occurs, you'll need to create a counter variable based on running a loop test that includes all program functions except the move asteroids function. For example, if you replace the code below about loading and displaying the movie frame with your game code (ship moving, anything other than the asteroids moving), that should be able to give you a pretty good estimate of what you need to set your asteroid delay counter to. Then you can just have your asteroid delay counter count down to zero, and call the move asteroids function when the counter runs down and reset the counter.
So, let's say you want the asteroids to move once every fifth of a second. After gauging the speed of your computer using code similar to what I have below, you will have a number that says how many times cycling through your program loop equals one second. Let's call that number progLoopsPerSec. Now you can just set a variable like asteroidCounter to equal 1/5 * progLoopsPerSec (because we want to move every fifth of a second, not every whole second) and decrease the counter variable each time through your program loop. Finally, create an IF/THEN statement in your main program loop that checks asteroidCounter to see if it has reached zero. If so, call the move asteroids function, and reset asteroidCounter to 1/5 * progLoopsPerSec again.
If you think this might be helpful, but it's too confusing, let me know, and I'll be glad to try and clarify or help implement this in your code.
Code: Select all
'This function gauges the speed of the current machine. The most cpu-intensive part of frame processing in this video program is the loading of the palette and the video frame to the screen. Gauge the speed of the current cpu by repeatedly processing a single frame. Note that other programs running in the background can affect the speed of loading from the test file. For best results, run this test without other programs running in tandem.
SUB getSpeed (file$)
asecs = 0
'More test cycles = more accurate results.
cyclesToTest = 800
'Get the current time.
a$ = TIME$
'Break down the current time into total seconds for the current day to avoid issues with gauging near the top of the hour or top of the minute.
ot = INT(VAL(MID$(a$, 1, 2)) * 360) + INT(VAL(MID$(a$, 4, 2)) * 60) + INT(VAL(MID$(a$, 7, 2)))
'Load in the test frame and its palette for as many cycles as previously indicated.
FOR x = 0 TO cyclesToTest
'Call a function that loads in the palette from the test file.
loadPalette file$
'Load the frame to the screen.
DEF SEG = &HA000
BLOAD file$ + sshExt$, 0
DEF SEG
NEXT
'Check the time again to see how long it took to run the test cycles.
'Get current time.
a$ = TIME$
'Break down time into seconds again.
t = INT(VAL(MID$(a$, 1, 2)) * 360) + INT(VAL(MID$(a$, 4, 2)) * 60) + INT(VAL(MID$(a$, 7, 2)))
'Check the difference to get the total number of seconds it took to run the test.
secs = t - ot
'Calculate this cpu's max frame rate by dividing the cycles tested by the amount of time it took to run the test cycles.
maxFps = INT(cyclesToTest / secs)
'Now find out how many empty FOR/NEXT loops this cpu can run in a second.
'Initialize the seconds variable.
secs = 0
'Test for about 10 million cycles; the higher the number of cycles, the more accurate the results.
cyclesToTest = 9999999
'Get the current time.
a$ = TIME$
'Break down the time into seconds.
ot = INT(VAL(MID$(a$, 1, 2)) * 360) + INT(VAL(MID$(a$, 4, 2)) * 60) + INT(VAL(MID$(a$, 7, 2)))
'Run the test.
FOR x = 0 TO cyclesToTest
NEXT
'Get the current time.
a$ = TIME$
'Break down the time into seconds.
t = INT(VAL(MID$(a$, 1, 2)) * 360) + INT(VAL(MID$(a$, 4, 2)) * 60) + INT(VAL(MID$(a$, 7, 2)))
'Calculate the difference to find the total amount of time it took to run the test (in seconds).
bsecs = t - ot
'If it took the cpu more than a second to run the test, calculate the cycles per second.
IF secs > 0 THEN
'Calculate the number of cycles the cpu has to run to delay one second.
cps = INT(cyclesToTest / secs)
ELSE
'This cpu is crazy fast. Just assume a cycles per second rate of about 10 million.
cps = 9999999
END IF
'Since we want to be able to adjust the frame rate of our video, calculate cycles per frame for this cpu.
'This number can be used to accurately enforce a user-designated frame rate.
cpf = INT(cps / maxFps)
END SUB