Help: Implementing Wave's FPS and DeltaTime

BlitzMax Forums/BlitzMax Beginners Area/Help: Implementing Wave's FPS and DeltaTime

Okay, I'm having trouble implementing Wave's DeltaTime type. I thought I followed his instructions exactly, but I'm very new at this so who knows?

If my implementation is correct, then maybe the type itself is buggy?

main program:
Strict

Include "DeltaTime.bmx"
Include "FPS.bmx"

	Delta.Start()
Type typeImageList
	Field image:TImage
	Field name:String
	
	Global imageList:TList

	Function Add(newFileName:String, newName:String )
		Local newImage:typeImageList
		
		newImage = New typeImageList
		
		newImage.image = LoadImage(newFileName)
		newImage.name = newName
		
		If imageList = Null Then
			imageList = CreateList()
		End If
		ListAddLast(imageList,newImage)
	End Function
	
	Function Get:TImage(searchName:String)
		Local currentImageList:typeImageList
		Local foundImage:TImage
		
		If imageList <> Null Then
			For currentImageList = EachIn imageList
				If currentImageList.name = searchName Then
					foundImage = currentImageList.image
				End If
			Next
		End If
		
		Return foundImage
	End Function				
End Type

Type typeSprite 
	Field image:TImage
	Field x
	Field y
	
	Method Draw()
		DrawImage(image,x,y)
	End Method
	
End Type

Type typeActor Extends typeSprite 
	Field xMove
	Field yMove
	Field rotDelta
	
	Method Update()
		x = x + (xMove*Delta.Time())
		y = y + (yMove*Delta.Time())
	End Method
End Type

Type typePlayer Extends typeActor
	Field health
	
	Method New()
		image = typeImageList.Get("Hero")
	End Method
	
	Method GetInputs()
		If KeyDown(KEY_LEFT) xMove:-1
		If KeyDown(KEY_RIGHT) xMove:+1
		If KeyDown(KEY_UP) yMove:-1
		If KeyDown(KEY_DOWN) yMove:+1
	End Method
	
End Type

Type typeEnemy Extends typeActor
	Field scoreValue			' how many points this enemy is worth
	
	Method New()
		scoreValue = 20			' all enemies have a default score value
	End Method
End Type

Type typeEnemyTurtle Extends typeEnemy
	Method New()
		image = typeImageList.Get("Turtle")
	End Method
End Type

Type typeEnemySnake Extends typeEnemy
	Method New()
		image = typeImageList.Get("Snake")
		scoreValue = 30
	End Method
End Type

Global imageEnemies:TImage[2]

Global RefreshRate=30     'Hz = FPS
Graphics 640,480,0,RefreshRate 



loadImages()

playGame()

End

Function loadImages()
	' Here you could read a text file to get the 2 strings
	' needed to create the named images
	typeImageList.Add("images/hero.png","Hero")
	typeImageList.Add("images/turtle.png","Turtle")
	typeImageList.Add("images/snake.png","Snake")
End Function

Function playGame()
	Local player:typePlayer
	Local enemyList:TList

	enemyList = CreateList()
	
	player = New typePlayer
	player.x = 100
	player.y = 50

	Local enemy:typeEnemy
	
	' create 1 turtle
	enemy = New TypeEnemyTurtle
	enemy.x = 200
	enemy.y = 200
	enemy.xMove = -1	' moving left
	ListAddLast(enemyList, enemy)

	' create 1 snake
	enemy = New TypeEnemySnake
	enemy.x = 240
	enemy.y = 200
	enemy.xMove = 1	' moving right
	ListAddLast(enemyList, enemy)


	While Not KeyHit(KEY_Escape)

		Cls
		Delta.Update()
		player.GetInputs()
		player.Update()

		For enemy = EachIn enemyList
			enemy.Update()
		Next
		
		player.Draw()
		
		For enemy = EachIn enemyList
			enemy.Draw()
		Next
		FPS.Display()
		Flip

	Wend
End Function	


Pretty much the only lines that refer to DeltaTime are these two lines from the update method of TypeActor:

x = x + (xMove*Delta.Time())
y = y + (yMove*Delta.Time())

For some reason, the turtle moves but the snake does not. Also, when the turtle hits the left side of the screen, it freezes. The player never moves. If I take out the reference to DeltaTime(), everything works as expected.

Here are the contents of FPS.bmx and DeltaTime.bmx, just in case I screwed something up while transcribing them:

FPS.bmx:
Type FPS
	' FPS_Counter <> Runs and displays the FPS
	Global Counter, Time, TFPS
	Function Calc%()
		Counter:+1
		If Time < MilliSecs()
			TFPS = Counter' <- Frames/Sec
			Time = MilliSecs() + 1000'Update
			Counter = 0
		EndIf
		Return TFPS
	EndFunction
	Function Display()
			DrawText "FPS: "+FPS.Calc(),10,10
	End Function
EndType


Delta Time
Type Delta
	'Delta Time code provided by Truplos@....
	Global DeltaTime#
	Global TimeDelay%
	Function Start()
		'Call Delta.Start() before main loop
		TimeDelay = MilliSecs()
	End Function
	Function Time#()
		'EXAMPLE:
		'use this:         	 Speed:+ 10*Delta.Time()
		'instead of this:   Speed:+ 10
		'WTF is it +Delta.Time() or *Delta.Time()?  The pdf says to multiply but that breaks my game!
		Return DeltaTime#
	End Function
	Function Update()
		'Call Delta.Update() once in the main loop.
		DeltaTime = ( MilliSecs()- TimeDelay )*0.001
		TimeDelay = MilliSecs()
	EndFunction
End Type


(Yes, I'm probabaly going to keep asking questions every step of the way on this simple little demo game until I figure out what the heck I'm doing.)

I think the problem is that variables default to be integers.
If you change the type sprite x and y variables to be floats

ie.

Field x:Float
Field y:Float

it should work.

Let's see...

Yep! :)

But, MAN, that sucks that int/float issues like that can sneak up on you like that. :x How can you tell when an issue like that is going to occur? And what about Strict? I thought the whole point of Strict was that it would force you to remove ambiguities and declare everything precisely?

Strangely enough, it doesn't seem to care whether xMove and yMove are declared floats or not. Why is that?

My int score is too low for programming. :( I'm gonna go drink a float. :)

If anyone cares, here is Wave's DeltaTime code, documented a bit more concisely (in my opinion):

Type Delta
	'Delta Time code provided by Truplos@....
	Global DeltaTime#
	Global TimeDelay%
	Function Start()
		'Call Delta.Start() before main loop
		TimeDelay = MilliSecs()
	End Function
	Function Time#()
		'EXAMPLE:
		'use this:         	 Speed:+ 10*Delta.Time()
		'instead of this:   Speed:+ 10
		'A value of 10 now means 10 per second!  Not 10 per frame!
		'Note: Variables (speed in this example) that get multiplied by Delta.Time() MUST be declared as a float!
		Return DeltaTime#
	End Function
	Function Update()
		'Call Delta.Update() once in the main loop.
		DeltaTime = ( MilliSecs()- TimeDelay )*0.001
		TimeDelay = MilliSecs()
	EndFunction
End Type


You set the xmove and ymove to and integer values so unless you want to use fractions for them they are fine.

The reason is :
When you calculate the new values for x and y you have have the calculation

x = x + (xMove*Delta.Time())
y = y + (yMove*Delta.Time())

Delta.Time() is a floating point ( The # is the same as declaring it as :Float )
because you are multiplying an integer value with a floating point blitzbasic makes the result a floating point which you then add to x ( which you have now made into a floating point value ).

There have been various threads in these forums regarding the definition of Strict and personally I agree with you that strict should 'force' you to declare the type of every variable and it should not default to integer. Or at least it should compile with a warning message for every variable that it defaults on you behalf.

Once you are aware that the default is an integer then if things go wrong you know where to look. Either that or get into the habit of fully specifying every variable you declare.

Okay. So int x float = float, but int + float = ERROR.

Gotcha. Thanks. :)

Is that how it works in Blitz3D, too?


Okay. So int x float = float, but int + float = ERROR.

Gotcha. Thanks. :)

Is that how it works in Blitz3D, too?

works almost the same it blitz3d and C++.



I made a table on float and int :)

int + float = a nice new float
int=float ' =possible loss of data
therefore int=int+float ' =loss of data probably!

a:int = c:float 'loss of data after c's decimal
d:float = c:float 'fine

a:int = b:int * c:float 'loss of data after the result's decimal
d:float = b:int * c:float 'fine

a:int = b:int + c:float 'loss of data after the result's decimal
d:float = b:int + c:float 'fine

I declare everything so that i dont run into these errors.

Jay, Hope it works now =)

Also don't miss that when using deltatime you need to apply it to everything that you increase every frame. Like X:+ XMove *Delta.Time() but also XMove:+ XAcceleration or Sheild:+ SheildRecharge*Delta.Time()

If you multiply a int with a float you get a float.
Ex:
local X# = 15/7 ' This will always return a int (=2) even though X is a float and the result is a float, because both values are ints. Compared to:
local X# = 15/7.0 Will make it work the right way. Because one of the values is a float - 7.0, Same goes with varables.

I declare everything so that i dont run into these errors.
That's what you have to do when you use Strict. Because:
Local X Will declare X as an Int, it's the default.
Local X# Will delcare it as a float.
Local X:Int - Declare as an Int (Same as first)
Local X:Float - Delcare as a Float (text style) same as X#

WarZone I'll add those comment to the delta function next time I update the guide, if that's ok. I'll take a look at the DeltaTime example too, perhaps I can make it more clear.

Also the Delta Function (Any code, not text, you find in the guide) is Public so you don't need to refer to me, you may also change it however you want and then sell it ;)

Wave, you are quite welcome to use my comments when you update your tutorial. :) Your long comments are great for users just learning how to write code, so it might be a good idea to include both versions. My brief comments are just for lazy people who just want your DeltaTime solution in all their games right now. :p

Now there is truly no excuse not to use DeltaTime! XD

Perfect, though I won't update the guide until mid september.