Thought I had posted this before, but as I can't find it, I'll do it now. Essentially, it is a movement multiplier, independent of computer speed.
All you need to do is call iniAppTime and then call updateAppTime in each loop, using the return value multiplied by a speed value
// --------------------------------- //
// Project: AppTimer
// Start: Thursday, September 11, 2008
// IDE Version: 5.360
//! This help file contains information for using the AppTiming system, which can be used to give a consistent movement speed
//! independant of the processor speed
//! The original code was for BlitzMax, and was written by Leadwerks
//! Converted to GLBasic by Nicholas Kingsley
//! You call the routines like :
//! initAppTime()
//! speed=updateAppTime()
TYPE tAppTime
AppTime_UPS
AppTime_Iterator
AppTime_CurrentTime
AppTime_PauseStart
AppTime_Speed
AppTime_DesiredLoopTime
AppTime_LastUpdateTime
AppTime_LastUPSTime
AppTime_DesiredFrequency%
ENDTYPE
GLOBAL _appTime AS tAppTime
//! This function initialises the AppTimer system, and must be called first.
//\param frameRate% - This is the frame rate that you want all movement to be based on. It defaults to 60 FPS, which is the lowest rate that should be used.
//\return Nothing is returned
FUNCTION initAppTime:frameRate%=60
_appTime.AppTime_UPS=0
_appTime.AppTime_Iterator=0
_appTime.AppTime_CurrentTime=0
_appTime.AppTime_PauseStart=0
_appTime.AppTime_Speed=1.0
_appTime.AppTime_DesiredLoopTime=1000.0/60.0
_appTime.AppTime_LastUpdateTime=0
_appTime.AppTime_LastUPSTime=0
_appTime.AppTime_DesiredFrequency%=frameRate%
ENDFUNCTION
//! This function updates the timing system. It needs to be called once per loop.
//\param No parameters are passed
//\return A movement value is returned. This should be muliplied by the amount you want to move. If the routine is paused, then 0.0 is returned
FUNCTION updateAppTime:
LOCAL time
LOCAL elapsed
IF _appTime.AppTime_PauseStart<>0
RETURN 0.0
ENDIF
_appTime.AppTime_DesiredLoopTime=1000.0/_appTime.AppTime_DesiredFrequency%
time=GETTIMERALL()
IF _appTime.AppTime_LastUpdateTime=0
_appTime.AppTime_Speed=1.0
_appTime.AppTime_LastUpdateTime=time
_appTime.AppTime_CurrentTime=time
_appTime.AppTime_LastUPSTime=time
ELSE
elapsed=time-_appTime.AppTime_LastUpdateTime
IF elapsed=0.0
elapsed=1.0
SLEEP 1
INC time,1.0
ENDIF
_appTime.AppTime_Speed=elapsed/_appTime.AppTime_DesiredLoopTime
_appTime.AppTime_CurrentTime=time
_appTime.AppTime_LastUpdateTime=time
ENDIF
INC _appTime.AppTime_Iterator,1
IF _appTime.AppTime_CurrentTime-_appTime.AppTime_LastUPSTime>=1000
_appTime.AppTime_UPS=_appTime.AppTime_Iterator/((_appTime.AppTime_CurrentTime-_appTime.AppTime_LastUPSTime)/1000)
_appTime.AppTime_LastUPSTime=_appTime.AppTime_CurrentTime
_appTime.AppTime_Iterator=0
ENDIF
RETURN _appTime.AppTime_Speed
ENDFUNCTION
//! This function is used when your program is paused or not. If it is, then the step speed is still updated
//\param pause% - If this is TRUE, then your program is paused. If FALSE, then it isn't
//\return Nothing is returned
FUNCTION pauseUnPauseAppTime:pause%
LOCAL elapsed
IF pause%=TRUE
IF _appTime.AppTime_PauseStart=0.0
_appTime.AppTime_PauseStart=GETTIMERALL()
_appTime.AppTime_UPS=0
_appTime.AppTime_Speed=0
ENDIF
ELSE
IF _appTime.AppTime_PauseStart<>0.0
IF _appTime.AppTime_LastUpdateTime<>0.0
elapsed=GETTIMERALL()-_appTime.AppTime_PauseStart
INC _appTime.AppTime_LastUpdateTime,elapsed
ENDIF
_appTime.AppTime_PauseStart=0.0
updateAppTime()
ENDIF
ENDIF
ENDFUNCTION
//! This function returns the time taken to complete a loop
//\param No parameters are passed
//\return Time taken (in milliseconds) to complete a loop
FUNCTION AppTime:
RETURN _appTime.AppTime_CurrentTime
ENDFUNCTION
//! This function returns the frame rate
//\param No parameters are passed
//\return Frame rate
FUNCTION AppSpeed:
RETURN _appTime.AppTime_Speed
ENDFUNCTION
//! This function returns the updates per second, and is an approximation
//\param No parameters are passed
//\return Updates per second
FUNCTION UPS:
RETURN _appTime.AppTime_UPS
ENDFUNCTION
hi
Any examples of this in use ?
Thanks
okee
Here is an example program, showing a bouncing ball :
LOCAL speed,x,y,dirX,dirY
initAppTime() // We want everything to be as near to 60FPS as possible
speed=0.0
x=100.0+(RND(16)-8)
y=100.0+(RND(16)-8)
dirX=1.0
dirY=1.0
WHILE TRUE
DRAWRECT x,y,16,16,RGB(255,0,0)
PRINT "Loop time : "+AppTime(),0,0
PRINT "Frame rate : "+AppSpeed(),0,12
PRINT "Updates per second : "+UPS(),0,24
SHOWSCREEN
INC x,speed*dirX*0.75
INC y,speed*dirY*0.75
IF x<40 OR x>200
dirX=0.0-dirX
ENDIF
IF y<40 OR y>200
dirY=0.0-dirY
ENDIF
speed=updateAppTime() // Update the timer
WEND
I have found that AppTimer produces more consistent results across multiple platforms than the simpler one of using the square of the screen width.
A very handy technique for cross-platform work, well done Mr. T. :good:
Its actually a conversion from Leadwerks BlitzMax code :) So I cant take all the credit, unfortunately :)
This is the version using the extended TYPE system :
// --------------------------------- //
// Project: AppTimer
// Start: Thursday, September 11, 2008
// IDE Version: 5.360
//! This help file contains information for using the AppTiming system, which can be used to give a consistent movement speed
//! independant of the processor speed
//! The original code was for BlitzMax, and was written by Leadwerks
//! Converted to GLBasic by Nicholas Kingsley
//! You call the routines like :
//! LOCAL blah AS TAppTime
//! blah.Initialise_AppTime()
//! speed=blah.Update_AppTime()
TYPE TAppTime
AppTime_UPS;AppTime_Iterator;AppTime_CurrentTime;AppTime_PauseStart;AppTime_Speed;AppTime_DesiredLoopTime;AppTime_LastUpdateTime
AppTime_LastUPSTime;AppTime_DesiredFrequency%
//! This function initialises the AppTimer system, and must be called first.
//\param frameRate% - This is the frame rate that you want all movement to be based on. It defaults to 60 FPS, which is the lowest rate that should be used.
//\return Nothing is returned
FUNCTION Initialise_AppTime%:frameRate%=60
self.AppTime_UPS=0
self.AppTime_Iterator=0
self.AppTime_CurrentTime=0
self.AppTime_PauseStart=0
self.AppTime_Speed=1.0
self.AppTime_DesiredLoopTime=1000.0/60.0
self.AppTime_LastUpdateTime=0
self.AppTime_LastUPSTime=0
self.AppTime_DesiredFrequency%=frameRate%
ENDFUNCTION
//! This function updates the timing system. It needs to be called once per loop.
//\param No parameters are passed
//\return A movement value is returned. This should be muliplied by the amount you want to move. If the routine is paused, then 0.0 is returned
FUNCTION Update_AppTime%:
LOCAL time
LOCAL elapsed
IF self.AppTime_PauseStart<>0
RETURN 0.0
ENDIF
self.AppTime_DesiredLoopTime=1000.0/self.AppTime_DesiredFrequency%
time=GETTIMERALL()
IF self.AppTime_LastUpdateTime=0
self.AppTime_Speed=1.0
self.AppTime_LastUpdateTime=time
self.AppTime_CurrentTime=time
self.AppTime_LastUPSTime=time
ELSE
elapsed=time-self.AppTime_LastUpdateTime
IF elapsed=0.0
elapsed=1.0
SLEEP 1
INC time,1.0
ENDIF
self.AppTime_Speed=elapsed/self.AppTime_DesiredLoopTime
self.AppTime_CurrentTime=time
self.AppTime_LastUpdateTime=time
ENDIF
INC self.AppTime_Iterator,1
IF self.AppTime_CurrentTime-self.AppTime_LastUPSTime>=1000
self.AppTime_UPS=self.AppTime_Iterator/((self.AppTime_CurrentTime-self.AppTime_LastUPSTime)/1000)
self.AppTime_LastUPSTime=self.AppTime_CurrentTime
self.AppTime_Iterator=0
ENDIF
RETURN self.AppTime_Speed
ENDFUNCTION
//! This function is used when your program is paused or not. If it is, then the step speed is still updated
//\param pause% - If this is TRUE, then your program is paused. If FALSE, then it isn't
//\return Nothing is returned
FUNCTION Pause_AppTime%:doPause%
LOCAL elapsed
IF doPause%=TRUE
IF self.AppTime_PauseStart=0.0
self.AppTime_PauseStart=GETTIMERALL()
self.AppTime_UPS=0
self.AppTime_Speed=0
ENDIF
ELSE
IF self.AppTime_PauseStart<>0.0
IF self.AppTime_LastUpdateTime<>0.0
elapsed=GETTIMERALL()-self.AppTime_PauseStart
INC self.AppTime_LastUpdateTime,elapsed
ENDIF
self.AppTime_PauseStart=0.0
self.Update_AppTime()
ENDIF
ENDIF
ENDFUNCTION
//! This function returns the time taken to complete a loop
//\param No parameters are passed
//\return Time taken (in milliseconds) to complete a loop
FUNCTION AppTime:
RETURN self.AppTime_CurrentTime
ENDFUNCTION
//! This function returns the frame rate
//\param No parameters are passed
//\return Frame rate
FUNCTION AppSpeed:
RETURN self.AppTime_Speed
ENDFUNCTION
//! This function returns the updates per second, and is an approximation
//\param No parameters are passed
//\return Updates per second
FUNCTION UPS:
RETURN self.AppTime_UPS
ENDFUNCTION
ENDTYPE
I will try it in my game! :nw:
I'm getting some odd readings from the Extended Type version of this code.
The following displays between 60 and 65fps when testing my game (with 60FPS limit) :
dtime = GETTIMER()
fps = 1000/dtime
fpstimer = fpstimer+dtime
IF fpstimer>500 // 1/2 sec
fpstimer = 0
realfps = fps
ENDIF
PRINT "FPS: "+realfps,640,570
If I call:
LOCAL moveTimer AS TAppTime
moveTimer.Initialise_AppTime(60)
outside of my main loop, and inside the loop:
moveTimer.Update_AppTime()
and then add:
newfps = moveTimer.AppSpeed()
PRINT "AS: "+newfps,640,520
The original FPS counter displays correctly at around 60fps, but AS flicks between 0 and 1, which obviously breaks any movement I tie into the returns from your functions.
Have I missed something out?
No - I made a slight mistake with the type of the function Update_AppTime - it shouldn't return integers, so just remove the % after the name.
It's taken me a couple of days to get to this, so apologies for the delay. Removing the % doesn't help. It still gives me between 0 and 1. AppTime_UPS gives me a set of numbers that looks about right though.
I'll have to look into that - I've never properly used AppSpeed for the FPS, so I'll have to see if thats correct.
One thing to note - the return value from the Update function is the one that should be used for movement speeds.
I've included the latest version as well, as now GLBasic allows functions with the same name in types, I've made the function names a bit quicker to type.
[attachment deleted by admin]
Don't worry too much, I'm going to convert some code from DarkBasic that averages the frame rate over x number of previous frames, and uses that to smooth out movement.
fair enough!