I'm rather pleased with the timing that I have for
this thing, so here is an example pulled from it.
(Also available
here).
What I am doing there is not keeping a consistent frame rate under the hood, but having the speed that the player sees completely consistent. This makes it easy for a few neat goodies like a game speed slider! (The speed can be consistently / reliably dealt with using FL\SpeedFactor).
The code compensates for slower than expected frame speed in a magical way, by adjusting FL\SpeedFactor.
The main program (with irrelevent stuff removed) (sorry, it's a bit strange):
;#Region Global Variables
Global Terminate = False ;Set this to True anywhere to terminate the program.
Global DefaultFR=30
Global Event
;Frame Limiter Initialization
Type FrameRate
Field TargetFPS#
Field SpeedFactor#
Field FPS#
Field TicksPerSecond
Field CurrentTicks
Field FrameDelay
End Type
Global FL.FrameRate = New FrameRate
FrameLimitInit(30.0)
;#End Region
;#Region Main Loop
Repeat
MainLoop()
Until Terminate
WB3D_EndGUI()
End
;#End Region
Function MainLoop(act=1)
SetSpeedFactor()
Event=WB3D_WaitEvent()
If act=1
Update()
EndIf
Render()
End Function
;Frame Limiter Functions:
Function FrameLimitInit(target_FPS#)
FL\TargetFPS# = target_FPS#
FL\TicksPerSecond = 1000
FL\FrameDelay = MilliSecs()
End Function
Function SetSpeedFactor()
FL\CurrentTicks = MilliSecs()
FL\SpeedFactor = (FL\CurrentTicks - FL\FrameDelay) / (FL\TicksPerSecond / FL\TargetFPS)
If FL\SpeedFactor <= 0 Then FL\SpeedFactor = 0.00000000001
FL\FPS = FL\TargetFPS / FL\SpeedFactor
FL\FrameDelay = FL\CurrentTicks
End Function
Then, for example, when Neutrons are moved, their movement per frame is based on something to do with the set speed and the frame rate. Again, very trimmed down, just to show the idea:
speed=2
n\angle = n\angle + Rand( (-180) * FL\SpeedFactor , (180) * FL\SpeedFactor )
n\x = n\x + ( (Sin(n\angle) * speed) * FL\SpeedFactor )
That was really weird, though. Here's a better example: Movement = NormalMovement * FL\SpeedFactor
And, somewhere in the updater I get the position of the little simulation speed slider: FL\TargetFPS=WB3D_GetTrackBarPos(guiSScroller)
That there sets the the target frame rate to that number. Note that this does
not place any delays anywhere. Even when the speed slider is at 0, the game will render and 'think' at the same speed. (It will just think of much smaller movements). Instead of forcing the frame rate to a particular amount, this method tries to cooperate with the current frame rate. This can cause problems with stuff like collision detection, though, since if it runs too slowly objects are made to move faster, so beware.
I got that timing code from somewhere, but I forget where unfortunately. Probably either these forums or BlitzCoder, of course.
It's nice and easy; just call FrameLimitInit() to start it up, then put SetSpeedFactor() in your main loop, and you can find the necessary types / functions in the code here. (That would be the FrameRate Type and the functions I mentioned). I take absolutely no credit for that code, by the way!