Code archives/Algorithms/AppTiming module

This code has been declared by its author to be Public Domain code.

Download source code

AppTiming module by JoshK2007
Any time-sensitive routine should be modulated by the application speed. This set of commands will make the task easier.

Call UpdateAppTime() once every game loop. You can specify a framerate your application should run at. The default value is 60.

Multiply every time-dependent value in your program with the function AppSpeed(). If the program is supposed to run at 60 FPS but it is running at 120, AppSpeed() will return 0.5.

AppTime() will return the same value until the next call to UpdateAppTime(). This ensures your entire game loop is always using uniform timing.

PauseApp() and ResumeApp() will stop and resume the application without effecting timing.

UPS() will return updates per second. The value is calculated once per second and rounded to an integer. This is not a precise measurement, but rather a visual approximation for printing to the screen.

Because of the limited resolution of the Millisecs() timer, the application will cap the UPS at 1000. A delay will be called to ensure that errors do not occur.


If you use this code, your application will always run at the same speed regardless of framerate.
Module leadwerks.apptiming

Private

Global AppTime_UPS
Global AppTime_Iterator
Global AppTime_CurrentTime
Global AppTime_PauseStart=0
Global AppTime_Speed:Float=1.0
Global AppTime_DesiredLoopTime#=1000.0/60.0
Global AppTime_LastUpdateTime=0
Global AppTime_LastUPSTime

Public

Rem
bbdoc:
EndRem
Function UpdateAppTime(framerate=60)
	Local time
	Local elapsed
	
	If AppTime_PauseStart Return
	
	AppTime_DesiredLoopTime=1000.0/framerate

	time=MilliSecs()

	If AppTime_LastUpdateTime=0
		AppTime_Speed#=1.0
		AppTime_LastUpdateTime=time
		AppTime_CurrentTime=time
		AppTime_LastUPSTime=time
	Else
		elapsed=time-AppTime_LastUpdateTime
		If Not elapsed
			elapsed=1
			Delay 1
			time:+1
		EndIf
		AppTime_Speed=Float(elapsed)/Float(AppTime_DesiredLoopTime)
		AppTime_CurrentTime=time
		AppTime_LastUpdateTime=time
	EndIf
	
	AppTime_Iterator:+1
	If AppTime_CurrentTime-AppTime_LastUPSTime>=1000
		AppTime_UPS=Float(AppTime_Iterator)/(Float(AppTime_CurrentTime-AppTime_LastUPSTime)/1000.0)
		AppTime_LastUPSTime=AppTime_CurrentTime
		AppTime_Iterator=0
	EndIf
	
EndFunction

Rem
bbdoc:
EndRem
Function AppTime()
	Return AppTime_CurrentTime
EndFunction

Rem
bbdoc:
EndRem
Function AppSpeed#()
	Return AppTime_Speed
EndFunction

Rem
bbdoc:
EndRem
Function UPS:Int()
	Return AppTime_UPS
EndFunction

Rem
bbdoc:
EndRem
Function PauseApp()
	If AppTime_PauseStart Return
	AppTime_PauseStart=MilliSecs()
EndFunction

Rem
bbdoc:
EndRem
Function ResumeApp()
	If Not AppTime_PauseStart Return
	If AppTime_LastUpdateTime
		Local elapsed=MilliSecs()-AppTime_PauseStart
		AppTime_LastUpdateTime:+elapsed
	EndIf
	AppTime_PauseStart=0
EndFunction

Comments

Dreamora2007
Hmm, wouldn't it make more sense if UPS returns 0 if paused and the same for AppSpeed?

Currently, it will remain on constant speed while paused even thought the world shouldn't change anymore ...

Fixed it would look like this:

Module leadwerks.apptiming

Private

Global AppTime_UPS
Global AppTime_Iterator
Global AppTime_CurrentTime
Global AppTime_PauseStart=0
Global AppTime_Speed:Float=1.0
Global AppTime_DesiredLoopTime#=1000.0/60.0
Global AppTime_LastUpdateTime=0
Global AppTime_LastUPSTime
Global AppTime_DesiredFrequency% 'mainly to avoid float rounding errors

Public

Rem
bbdoc:
EndRem
Function UpdateAppTime(framerate=60)
	Local time
	Local elapsed
	
	If AppTime_PauseStart Return
	AppTime_DesiredFrequency = framerate
	AppTime_DesiredLoopTime=1000.0/framerate

	time=MilliSecs()

	If AppTime_LastUpdateTime=0
		AppTime_Speed#=1.0
		AppTime_LastUpdateTime=time
		AppTime_CurrentTime=time
		AppTime_LastUPSTime=time
	Else
		elapsed=time-AppTime_LastUpdateTime
		If Not elapsed
			elapsed=1
			Delay 1
			time:+1
		EndIf
		AppTime_Speed=Float(elapsed)/Float(AppTime_DesiredLoopTime)
		AppTime_CurrentTime=time
		AppTime_LastUpdateTime=time
	EndIf
	
	AppTime_Iterator:+1
	If AppTime_CurrentTime-AppTime_LastUPSTime>=1000
		AppTime_UPS=Float(AppTime_Iterator)/(Float(AppTime_CurrentTime-AppTime_LastUPSTime)/1000.0)
		AppTime_LastUPSTime=AppTime_CurrentTime
		AppTime_Iterator=0
	EndIf
	
EndFunction

Rem
bbdoc:
EndRem
Function AppTime()
	Return AppTime_CurrentTime
EndFunction

Rem
bbdoc:
EndRem
Function AppSpeed#()
	Return AppTime_Speed
EndFunction

Rem
bbdoc:
EndRem
Function UPS:Int()
	Return AppTime_UPS
EndFunction

Rem
bbdoc:
EndRem
Function PauseApp()
	If AppTime_PauseStart Return
	AppTime_PauseStart=MilliSecs()
        AppTime_UPS = 0
        AppTime_Speed = 0
EndFunction

Rem
bbdoc:
EndRem
Function ResumeApp()
	If Not AppTime_PauseStart Return
	If AppTime_LastUpdateTime
		Local elapsed=MilliSecs()-AppTime_PauseStart
		AppTime_LastUpdateTime:+elapsed
	EndIf
	AppTime_PauseStart=0
        UpdateAppTime( AppTime_DesiredFrequency )
EndFunction



slenkar2007
thanks leadwerks and dreamora, we need a standard (and easy) way to fix framerate


JoshK2007
If the user is calling AppSpeed() and UPS() while the application is paused they are doing something wrong. Pause and resume are for menus or GUI applications, where you stop the game loop and do some other unrelated stuff.


Code Archives Forum