Error in Jump & Run Collision

Blitz3D Forums/Blitz3D Beginners Area/Error in Jump & Run Collision

wesker_re(Posted 2008) [#1]
Hi,

i have found this BMax Code somewhere in this forum:

SuperStrict

Graphics 800 , 600 , 0

Const Gravity:Float = .1


Type TPlayer
	Field x:Float,y:Float
	Field width:Float , height:Float
	Field speedx:Float , speedy:Float
	
	
	Method Draw()
		DrawRect x , y , width , height
	EndMethod
	
	Method Update() 
		
		'ground friction
		speedx:* .85
		
		'x conrtols
		If KeyDown(key_left) Then speedx = - 2
		If KeyDown(key_right) Then speedx = 2
		
		'x movement
		x:+ speedx
		
		'if you ran into a wall
		If map.rectcollide(x , y , width , height) Then
			'move back out of the wall
			x:- speedx
			'stop your speed
			speedx = 0
		EndIf
		
		
		'y controls (jump)
		If KeyHit(key_up) Then
			'make sure you are on the ground
			If map.rectcollide(x , y + 1 , width , height) Then
				'jump!
				speedy = - 5
			EndIf
		EndIf
		
		'y movement
		speedy:+ gravity
		y:+ speedy
		
		'if you hit a wall
		If map.rectcollide(x , y , width , height) Then
			'move back out of the wall
			y:- speedy
			'stop your speed
			speedy = 0
		EndIf
		
	EndMethod
EndType


Type TMap
	Field width:Int , height:Int
	Field array:Int[,]
	Const tilesize:Int = 30
	
	Method Load()
		Local x:Int,y:Int
		Local line:String
		
		ReadData width
		ReadData height
		
		array=New Int[width,height]
		
		For y = 0 Until height
			ReadData line
			For x = 0 Until width
				array[x , y] = Int(Mid(line , x + 1 , 1) )
			Next
		Next
	EndMethod
	
	
	Method Draw()
		Local x:Int , y:Int
		
		For y = 0 Until height
			For x = 0 Until width
				If array[x , y] = 1 Then
					DrawRect x * tilesize , y * tilesize , tilesize , tilesize
				EndIf
			Next
		Next
	EndMethod
	
	
	'Returns True if the rectangle collides with the map.
	'This one and only collision function can be used for everything.
	Method RectCollide:Int(x:Float , y:Float , width:Float , height:Float)
		Local x1:Int , y1:Int
		Local x2:Int , y2:Int
		
		'convert pixel positions to tile positions
		x1 = x / tilesize
		y1 = y / tilesize
		x2 = (x + width) / tilesize
		y2 = (y + height) / tilesize
		
		Local tilex:Int , tiley:Int
		
		'check each tile that the rect is in
		For tiley = y1 To y2
			For tilex = x1 To x2
				If array[tilex , tiley] = 1 Then
					Return True
				EndIf
			Next
		Next
		
		Return False
	EndMethod
	
EndType



Global You:tplayer = New tplayer
you.x = 200
you.y = 100
you.width = 20
you.height = 25


Global Map:tmap = New tmap
map.load()



Repeat
	you.update()
	you.draw()
	map.draw()
	Flip
	Cls
	If KeyHit(key_escape) Then End
Forever



DefData 20,15
DefData "11111111111111111111"
DefData "11010101010101010101"
DefData "10000000000000000001"
DefData "11110000000000111111"
DefData "10000000000000000001"
DefData "10000000000000000001"
DefData "10000000111100000001"
DefData "10000000000000000001"
DefData "11110000000000000001"
DefData "10000000000000000001"
DefData "10000000001110001111"
DefData "10000000000000000001"
DefData "10000000000000000001"
DefData "10000000000000000001"
DefData "11111111111111111111"


I have convert the code zu Blitz3D:

Graphics 800,600,16,2
SetBuffer BackBuffer()

Global MAPWIDTH 	= 20
Global MAPHEIGHT 	= 15

Global TILESIZE 	= 32

Global Mode = 1

Dim Map(MAPWIDTH,MAPHEIGHT)

Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
Data 1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

For Y = 1 To MAPHEIGHT
	For X = 1 To MAPWIDTH
		Read Map(X,Y)
	Next
Next

Const Gravity# = .3

Type TPlayer
	Field X#
	Field Y#
	Field Width#
	Field Height#
	Field SpeedX#
	Field SpeedY#
End Type

Player.TPlayer = New TPlayer
Player\X# = 200
Player\Y# = 100
Player\Width# = 32
Player\Height# = 64

Global t = CreateTimer(60)

; ################################################

Function DrawScreen()

	For X = 0 To MAPWIDTH
		For Y = 0 To MAPHEIGHT
			Select Map(X,Y)
				Case 1
					Color 250,250,250
					If Mode = 0
						Rect(X*TILESIZE-16,Y*TILESIZE-16,TILESIZE,TILESIZE,1)
					ElseIf Mode = 1 
						Rect(X*TILESIZE,Y*TILESIZE,TILESIZE,TILESIZE,1)
					EndIf
			End Select
		Next
	Next
	
	For Player.TPlayer = Each TPlayer
		Rect(Player\X,Player\Y,Player\Width,Player\Height)		
	Next
	
End Function

; ################################################

Function Update()

	If KeyHit(57) Mode = 1 - Mode
	
	For Player.TPlayer = Each TPlayer
		
		; ground friction
		Player\SpeedX = Player\SpeedX * .85		
		
		; x controls
		If KeyDown(203) Player\SpeedX = -2
		If KeyDown(205) Player\SpeedX = 2
		
		; x movement
		Player\X = Player\X + Player\SpeedX
		
		; i you ran into a wall
		If Collide(Player\X,Player\Y,Player\Width,Player\Height)
			; move back out of the wall
			Player\X = Player\X - Player\SpeedX
			; stop your speed
			Player\SpeedX = 0
		EndIf
		
		; y controls (jump)
		If KeyHit(200) 
			; make sure you are on the ground
			If Collide(Player\X,Player\Y+1,Player\Width,Player\Height)
				; jump
				Player\SpeedY = - 10
			EndIf
		EndIf
		
		; y movement
		Player\SpeedY = Player\SpeedY + Gravity
		Player\Y = Player\Y + Player\SpeedY
		
		; if you hit a wall
		If Collide(Player\X,Player\Y,Player\Width,Player\Height)
			;move back out of the wall
			Player\Y = Player\Y - Player\SpeedY
			; stop your speed
			Player\SpeedY = 0
		EndIf
		
	Next
		
End Function

; ################################################

Function Collide(X#,Y#,Width#,Height#)

	Local X1
	Local Y1
	Local X2
	Local Y2
	
	; convert pixel positions To tile positions
	X1 = X / TILESIZE
	Y1 = Y / TILESIZE
	X2 = (X + Width) / TILESIZE
	Y2 = (Y + Height) / TILESIZE
	
	Local TileX
	Local TileY
	
	; check Each tile that the Rect is in
	For TileX = X1 To X2
		For TileY = Y1 To Y2
			If Map(TileX,TileY) = 1 Then
				Return True
			EndIf
		Next
	Next	
	
	Return False
	
End Function

; ################################################

Repeat

	WaitTimer(t)

	Cls
	
	Update()
	
	DrawScreen()
	
	Flip 0


Until KeyHit(1) : End

It works basically, but all the collisions are set -16 pixels. When i paint the Level -16px all is ok. But this cant be the right way. (Press Space to see what i mean)

Can anyone tell me what is the error?

Sry for my bad english,
Lucius


Ross C(Posted 2008) [#2]
Your best using blitzbasic's own collision routines for 2d graphics. Mainly imagesoverlap() and imagescollide().

bMAX works with 3D graphics and therefore has to use a slower detection method. I'm not saying that the code won't work though :o)

I'm in work and can't help you with the code i'm afraid.


wesker_re(Posted 2008) [#3]
This collision code is based on positions, not on the images.

But thanks anyway.

Any other users that can help?


WolRon(Posted 2008) [#4]
My guess is that it has something to do with this code:
; convert pixel positions To tile positions
	X1 = X / TILESIZE
	Y1 = Y / TILESIZE
	X2 = (X + Width) / TILESIZE
	Y2 = (Y + Height) / TILESIZE
Maybe you have to subtract 1/2 tile to compensate for rounding errors?
X1 = X / TILESIZE - .5


(Sorry for not knowing for sure...I'm very tired and can barely stay awake :)


wesker_re(Posted 2008) [#5]
Yes, you are right with the rounding errors. Thank you! :)