TimeLapse lib

Posted by on August 5, 2009

This little lib is used to keep track of time using the low resolution timer provided by the OS (in Windows “GetTickCount”). The goal of this type of library is to encapsulate timing actions. It was originally designed for game development in mind but needless to say you can use it and adapt it to your own needs.

Basically you define a time interval as you create the “timelapse” instance. Every time you call the update function a simple check determines whether the time was reached or not. This is trivial, but encapsulating it makes sense. Specially if you plan to create an animation system in the future!


The code:

EnableExplicit
 
Prototype.i TimeLapse_Callback( *this.i )
 
Structure TIMELAPSE
	old_time.i			; Stores the "old" time value.
	new_time.i			; Stores the "new" time value.
	time_out.i			; Time period for the TimeLapse , in ms.
	*callback.TimeLapse_Callback	; User callback.
	userdata.i			; User data.
EndStructure
 
CompilerSelect #PB_Compiler_OS
	CompilerCase #PB_OS_Windows
		Macro _time() : timeGetTime_()		: EndMacro
	CompilerDefault
		Macro _time() : ElapsedMilliseconds()	: EndMacro
CompilerEndSelect
 
Procedure.i TimeLapseCreate( Timeout.i, *Callback.TimeLapse_Callback = #Null, UserData.i = #Null )
 
	Define.TimeLapse  *this = AllocateMemory( SizeOf(TimeLapse ) )
 
	If *this
 
		With *this
			\new_time 	= _time()
			\old_time 	= *this\new_time
			\time_out	= Timeout
			\callback	= *Callback
			\userdata	= UserData
		EndWith
 
		ProcedureReturn *this
 
	EndIf
 
EndProcedure
 
Procedure.i TimeLapseDestroy( *this.TIMELAPSE  )
 
	If *this
 
		FreeMemory(*this)
		*this = #Null
		ProcedureReturn *this
 
	EndIf
 
EndProcedure
 
Procedure.i TimeLapseUpdate( *this.TIMELAPSE  )
 
	If *this
 
		*this\new_time = _time()
 
		If ((*this\new_time - *this\old_time) => *this\time_out)
 
			*this\old_time = *this\new_time
 
			If *this\callback
				ProcedureReturn *this\callback( *this )
			EndIf
 
			ProcedureReturn #True
 
		EndIf
 
	EndIf
 
EndProcedure
 
 
; Helper routines
 
Procedure.i TimeLapseSet( *this.TIMELAPSE , Timeout.i )
 
 	If Timeout > 0
		*this\time_out = Timeout
	EndIf
 
EndProcedure
 
Procedure.i TimeLapseGet( *this.TIMELAPSE  )
 
 	ProcedureReturn *this\time_out
 
EndProcedure

Example:

If OpenConsole()
	Define.TIMELAPSE  *test_timer  = TimeLapseCreate( 500 )
	Repeat

		If TimeLapseUpdate( *test_timer  )
			PrintN(" Timer says hi!" )
		EndIf

		Delay(10)
	Until Inkey() = Chr(27)
	CloseConsole()
EndIf
End

The nice thing about this library is the ability to use callbacks. Whenever a callback is defined, once the timer reaches the maximum allowed time-lapse, it’ll return by executing the callback.

In the callback you can do anything you want; From simple event triggering to manipulating another timer depending on XYZ conditions: it’s up to you!.

Just keep in mind: Always return “true” unless you want to invalidate the update call.

Here is a more advanced example with a callback, user data and multiple timers:

Procedure.i MyCallback( *this.TIMELAPSE  )

	; It's imperative that you return #true (1) in your callbacks if you want the "Update" calls to pass once the timeout is reached.
	; This is a design choice for flexibility and nothing else.

	ConsoleColor(Random(15), Random(15))
	PrintN(" Hi from the callback! ")

	PrintN( " The other timer is set to: " + Str( TimeLapseGet( *this\userdata ) ) + "ms" )
	PrintN( " ...Reducing the time interval down by 50 ms... " )

	TimeLapseSet( *this\userdata, TimeLapseGet( *this\userdata ) - 50 )
	ConsoleColor(15, 0)

	ProcedureReturn #True

EndProcedure

Define.TIMELAPSE  *timer_one 	= TimeLapseCreate( 500 )				; The first TimeLapse , nothing special.
Define.TIMELAPSE  *timer_two 	= TimeLapseCreate( 2000, @MyCallback(), *timer_one )	; The second TimeLapse , it manipulates the first one through a callback.
Define.TIMELAPSE  *timer_three	= TimeLapseCreate( 20*1000 )				; This TimeLapse  will simply let us exit the example after the set time.

If OpenConsole()

	EnableGraphicalConsole(1)
	ConsoleColor(15, 0)

	Define.i quit = #False

	Repeat

		If TimeLapseUpdate( *timer_three )
			quit = #True
		Else
			If TimeLapseUpdate( *timer_one )
				PrintN("timer_one: " + Str(*timer_one\time_out) + "ms reached.")
			EndIf
			If TimeLapseUpdate( *timer_two )
				PrintN("timer_two: " + Str(*timer_two\time_out) + "ms reached.")
			EndIf
		EndIf

		Delay(10)

	Until Inkey() = Chr(27) Or quit 

	PrintN( "timer_three: The example finished." )

	TimeLapseDestroy(*timer_one)
	TimeLapseDestroy(*timer_two)
	TimeLapseDestroy(*timer_three)

	Input()
	CloseConsole()

EndIf
End

The examples are crude, but they show every function in the library.
Should you have any questions, feel free to ask.

I’ll soon post the “Animation” lib that depends on “TimeLapse”.

Cheers.

2 Comments on TimeLapse lib

Closed

  1. GuShH says:

    Updated the base code, added the _time() macro. ( Internally ElapsedMilliseconds() resolves to GetTickCount() in Windows, this has a resolution of ~10ms which isn’t enough in some cases )

    I found no need to manually set the minimum resolution for timeGetTime() but if you want to make sure you can always add the timeBeginPeriod / timeEndPeriod block with the desired minimum resolution. Just don’t do this on every iteration of your code.

  2. […] on the time-lapse lib, the animation code provides you with several count methods to manipulate your animations in an […]