|  | 
 
 So you've got a great game. It's fun, it looks great, and your friends think it's the best thing since Pac-Man. You put it up for a public beta, and that's when the reports start coming in..."It seems nice, but the little guy is going at warp nine!" "I only last a second before I hit the spikes, seems it's going a little too fast." "Isn't there any way you can slow this %$%#%!! game down???" You're running the game on a P3 and it's fine, none of your friends have this problem... what happened, and how do you fix it? The WhysWhat you're running into is the convergence of several things: a trick Blitz uses to make screen draws nice and smooth, the way monitors work in general, and the ability of power users to completely screw up the works in order to attain higher 3D framerate. For starters, Blitz's innocuous FLIP command comes with two flavors: VWAIT-enabled and VWAIT-disabled. It's easy to miss, as the BB help files list no parameters to pass to FLIP (though the context-sensitive help given by hitting F1 twice reveals that it does indeed take a single parameter). What's the difference? The VWAIT-Enabled version automatically waits for your monitor to refresh itself before repainting the screen, which means it will automatically limit frames to as many per second as your monitor's refresh rate. If your monitor refreshes at 60hz, you'll get 60fps -- 70hz = 70fps, and so forth. At first glance it's a cheap way to do frame limiting, but it's not consistent, as it depends on the monitor's refresh rate, which varies from lows of 50 or so to highs of over 120. Now things get even worse: some power users disable a program's ability to use VWAIT by disabling the VSync signal on their video card.  When they do this, the program ALWAYS thinks a VWAIT has just happened, and it will redraw the screen immediately after each loop.  Suddenly, your nice little program that was running at 75fps (same as your monitor refresh) is doing 360 on some poor guy's P4/2G machine.  
 There's two ways to do this: the easy way out, and the complete solution. Sometimes you only need the easy way out, which is why I'm going to mention it -- but occasionally you'll need a more full-featured solution, which is what the point of the article is. :) The Easy Way OutThe easy way out involves Blitz's own internal CreateTimer and WaitTimer commands. The concept's simple: you create a timer that updates as many times per seconds as you want frames drawn, then before you flip the buffers you wait until the timer has ticked and then do the draw. It's a nice, clean, simple solution, but it's incredibly inefficient. It restricts your program from doing ANYTHING whle it's waiting for the timer to fire, and so you restrict your processing loops to once per display loop. This can drain resources if you have a lot of AI, pathfinding or effects going on. I won't post a sample here, as you can go into the BB IDE and find the help for CreateTimer and WaitTimer yourself (and Shane already did a perfectly good sample program that demonstrates their use). The Better WayThe more full-featured solution involves a little more work. The theory is to check how long it takes to run through each processing loop and modify your game objects' movement by a percent that reflects how quickly or slowly your machine is threading through the loops. This way you don't lose any cycles just waiting, and you can update the screen as often as your loop completes without making a game unplayable. There are three components to the full-featured solution: a Type declaration, two functions that use that type, and then your implementation of those functions (and the Global Type) in your game. Laying the FoundationThe type declaration is simple: 
 
 
 I use a global Type instance to keep track of all this info rather than a bunch of global variables, just because it's easier for me to keep organized. So, next, I do just that: make a global instance of this type: 
 Next, you want a nice function to set up all the initial values of that type instance, so all you have to do is enter in your target FPS and the function does the rest: 
 All it does is plop the target FPS into the right slot, set the TicksPerSecond to equal a millisecond (not terribly useful for Blitz right now, but useful if the timer ever becomes different than a millisecond counter), and then slots the current time, in milliseconds, into its proper place -- this value is used to get the actual speed per loop. To use it, all you need to do is pass it your desired FPS rate: 
 Now we're getting to the meat of this all. There's two things you need to have in order to do this properly: 
 Lectures aside, here's the function: 
 I'm not getting into a long-winded discussion about why this works; basically, it compares how many frames per second you're achieving, compares it to the frames per second you want to achieve, and sets the SpeedFactor to automatically adjust your in-game speeds. If, say, you set it for 30FPS, but you were achieving 60, then your SpeedFactor would be set to 0.5 -- everything in the game would move half as fast, achieving some lovely ultra-smooth movement. On the other hand, if you had a low-end machine and were only achieving 15FPS, your SpeedFactor would be set to 2.0 -- the game would be a lot jerkier, but it would appear to be running at the same speed as the faster machine. If you want to see the nuts and bolts for yourself, read this article on gamedev.net for a far better explanation than I can muster. Using the LimiterWith everything set up, all you need to do now is: 
 As a quick, short example, if you originally moved your player object like this: 
 You'd now move it like this: 
 And that's everything! I hope this has helped with questions about framerate-independent game movement, and that the code will help you get your games running smooth on everyone's rigs. Feel free to email me -- morduun@hotmail.com -- if you have any questions, and good luck with your game! 
 
 
 For a printable copy of this article, please click HERE. 
 This site is Copyright© 2000-2004, BlitzCoder. All rights reserved.   |