Here is my take on deWitters famous game loop code. It makes for a smoother game, runs you code at same speed on any platform too.
This removes the need for your program to update its logic at the same time as the frame is rendered (why check for a key press at 60 fps for example). Also, your code does not need to wait till a frame is rendered to continue. Another advantage is predicted interpolation, this means for much smoother graphics with a more powerful platforms or "best fit" with low powered platforms. On top of that you can choose at what frame speed your game runs at, without worrying about the speed the graphics are being rendered at, great for physics simulations for example. The chances are that if you have seen a really smooth game running on different platforms, then it uses code like this.
About the demo:
The demo code is based on a small code listing from here,
http://www.glbasic.com/forum/index.php?topic=8425.msg71420#msg71420I simply converted it, to show you how a traditional gameloop piece of code would be converted to run with independent game logic. Its not the best example (the juddering when the two boxes meet is because of the original code) but I did not want to change it further to add confusion
Important:
Set "Maximum Frame rate [hz]" to -1 in your project options Also on some GFX cards you may have to "Vertical Sync" off if it is forced on in your driver options.
Read This:
http://www.koonsolo.com/news/dewitters-gameloop/This explains it better than I ever could.
New Game Loop Lib:
// --------------------------------- //
// Project: gameloop (Ian Thompson - Sept 12)
// Start: Wednesday, September 05, 2012
// IDE Version: 11.001
// Based on "deWiTTERS Game Loop" ( see http://www.koonsolo.com/news/dewitters-gameloop/ )
GLOBAL interpolation#
FUNCTION GameLoop:
CONSTANT TICKS_PER_SECOND% = 30 // Runs at 30fps
CONSTANT SKIP_TICKS% = 1000 / TICKS_PER_SECOND
CONSTANT MAX_FRAMESKIP% = 5
LOCAL next_game_tick% = GETTIMERALL()
LOCAL loops%
LOCAL game_is_running% = TRUE
WHILE( game_is_running )
loops% = 0
WHILE( GETTIMERALL() > next_game_tick% AND loops < MAX_FRAMESKIP%)
Update()
next_game_tick = next_game_tick + SKIP_TICKS
INC loops
WEND
interpolation# = ( GETTIMERALL() + SKIP_TICKS - next_game_tick ) / SKIP_TICKS
Render()
WEND
ENDFUNCTION
FUNCTION Interpolate#: cur#, old#, interp#
RETURN old# + (cur# - old#) * interp#
ENDFUNCTION
Demo:
// --------------------------------- //
// Project: Constant Game Speed independent of Variable FPS demo (Ian Thompson - Sept 12)
// Start: Wednesday, September 05, 2012
// IDE Version: 11.001
GLOBAL x#=100,Ox#
GLOBAL y#=100,Oy#
GLOBAL angle#=0
GLOBAL speed#=4
GLOBAL mx#,my#,Omx#,Omy#,b1,b2
SETSCREEN 640,480,0
WHILE TRUE
GameLoop()
WEND
// These two routines are the basis of your new game loop
// Only for game logic updating
FUNCTION Update:
LimitMouse()
MoveObjectToMouse()
ENDFUNCTION
// Only for drawing
FUNCTION Render:
DRAWRECT Interpolate(mx,Omx,interpolation#),Interpolate(my,Omy,interpolation#),32,32,RGB(255,0,0) // Mouse#
DRAWRECT Interpolate(x,Ox,interpolation#),Interpolate(y,Oy,interpolation#),32,32,RGB(255,255,255) // Object
PRINT "Rendering at "+getfps()+" FPS",10,10
SHOWSCREEN
ENDFUNCTION
FUNCTION LimitMouse:
Omx=mx;Omy=my // Cache anything that moves(or scales, rotates) before they change for frame by frame interpolation.
MOUSESTATE mx, my,b1, b2
IF mx<0 THEN mx=0
IF mx>640-32 THEN mx=640-32
IF my<0 THEN my=0
IF my>480-32 THEN my=480-32
// SETMOUSE mx, my
ENDFUNCTION
FUNCTION MoveObjectToMouse:
Ox=x;Oy=y // Cache anything that moves(or scales, rotates) before they change for frame by frame interpolation.
angle = ATAN(my - y, mx - x)
x=x+COS(angle)*speed
y=y+SIN(angle)*speed
ENDFUNCTION
//Frames per sec calc
FUNCTION getfps:
STATIC fps_time,fps_counter,fps,fps_temp
fps_time = GETTIMERALL()
fps_counter = fps_counter + 1
IF (fps_time-fps_temp)>1000
fps_temp = fps_time
fps = fps_counter
fps_counter = 0
ENDIF
RETURN fps
ENDFUNCTION
// Orginal frame based code ( see http://www.glbasic.com/forum/index.php?topic=8425.msg71420#msg71420 )
//GLOBAL x#=100
//GLOBAL y#=100
//GLOBAL angle#=0
//GLOBAL speed#=20
//
//GLOBAL mx#,my#,b1,b2
//
//SETSCREEN 640,480,0
//
//WHILE TRUE
//
// PRINT mx,10,10
// PRINT my,10,20
//
// LimitMouse()
//
// DRAWRECT mx,my,32,32,RGB(255,0,0) // Mouse#
// DRAWRECT x,y,32,32,RGB(255,255,255) // Object
//
// MoveObjectToMouse()
//
// SHOWSCREEN
//
//WEND
//
//FUNCTION LimitMouse:
// MOUSESTATE mx, my,b1, b2
// IF mx<0 THEN mx=0
// IF mx>640-32 THEN mx=640-32
// IF my<0 THEN my=0
// IF my>480-32 THEN my=480-32
// SETMOUSE mx, my
//ENDFUNCTION
//
//FUNCTION MoveObjectToMouse:
// angle = ATAN(my - y, mx - x)
// x=x+COS(angle)*speed
// y=y+SIN(angle)*speed
//ENDFUNCTION
I hope this of use to someone.
Ian
[attachment deleted by admin]