Collision problem

Blitz3D Forums/Blitz3D Beginners Area/Collision problem

elseano(Posted 2007) [#1]
So I'm trying to work out some code for collision detection, but there's something wrong with it. It seems to only detect a collision between the 'player' and the last "tile" type placed/loaded onto the map, rather than any tile on the map. I honestly can't see what's going wrong. Can anyone tell me why this is happening?

Many thanks to anyone who can help me with this.

;tiles test
;Sean Tomlin
;
;Last updated 13th June 07

;;;;;;;;;;;;;;;;;;;;;
;
;Space to save map
;Comma to load map
;Left mouseclick = place tile
;Delete + mouseclick = delete tiles
;Right mouseclick + move mouse = move around map
;Up/Down = change tile
;
;;;;;;;;;;;;;;;;;;;;;

Global tnumber = 0
Global maprx
Global mapry
Global maprmode

Global ox = 0
Global oy = 0

Global gravity# = 0.01

Graphics 640,480,16,1

SetBuffer BackBuffer()

ClsColor 134,156,175

;load tileset
Global tiles1=LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
MaskImage tiles1,255,0,255


Global px
Global py
Global pxspeed
Global pyspeed
Global pfalling=1

Global x
Global y

Global count
Global tilecount


;;;;;;;;;;;;;

While Not KeyHit(1)

	Cls
	
	Origin ox,oy
	
	UpdateMouse()
	
	If KeyHit(27) And tnumber<15 Then tnumber=tnumber+1
	If KeyHit(26) And tnumber>0 Then tnumber=tnumber-1
	
	If KeyHit(57) Then
	
		SaveMap()
		Text 10,290,"Save"
		
	EndIf
	
	
	If KeyHit(51) Then LoadMap()
	If KeyHit(14) Then ClearMap()

	UpdateTiles()	
	UpdatePlayer()
	
	Text 10,10,x/16
	Text 10,30,y/16
	
	Text 10,180,maprx
	Text 10,200,mapry
	Text 10,220,maprmode

	Flip
	
Wend

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Type tile

;position within grid
Field xnum
Field ynum

;type of tile: ground, water or danger
Field mode

End Type

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function UpdateMouse()
	
	;infiinite mouse movement
	xs=MouseXSpeed()
	ys=MouseYSpeed()
	MoveMouse 320,240
	
	;right mouse button (click + drag): move around map	
	If MouseDown(2) Then
		ox=ox+xs
		oy=oy+ys
	Else
		x=x+xs
		y=y+ys
	EndIf
	
	;draw the currently selected tile at mouse cursor
	DrawImage tiles1,x,y,tnumber
	
	Color 45,200,75
	Rect x,y,16,16,0
	
	;LMB: place tile
	If MouseDown(1) Then 
	
	If Not KeyDown(58) Then
			
		t.tile = New tile
		t\xnum = x/16
		t\ynum = y/16 
		t\mode = tnumber
			
	Else
	
		;4x tile if CAPS pressed also
		t.tile = New tile
		t\xnum = x/16
		t\ynum = y/16 
		t\mode = tnumber
		
		t.tile = New tile
		t\xnum = (x/16)+1
		t\ynum = y/16 
		t\mode = tnumber
		
		t.tile = New tile
		t\xnum = x/16
		t\ynum = (y/16)+1
		t\mode = tnumber
		
		t.tile = New tile
		t\xnum = (x/16)+1
		t\ynum = (y/16)+1
		t\mode = tnumber
		
	EndIf
			
	EndIf
	

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function UpdateTiles()

	For t.tile = Each tile

		DrawImage tiles1,t\xnum*16,t\ynum*16,t\mode
				
		If ImageRectOverlap(tiles1,t\xnum*16,t\ynum*16,x,y,14,14) Then
		
			If KeyDown(211) Then 
			
				Delete t
				
			Else 
			
		EndIf

		
		If ImageRectOverlap(tiles1,t\xnum*16,t\ynum*16,px,py,16,26) Then
			
			pfalling = 0
		
		Else
		
			pfalling = 1
			
		EndIf
	
	Next

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function UpdatePlayer()

	If KeyDown(205) Then
		
		If pxspeed<1.8 Then pxspeed=pxspeed+0.1
		
	ElseIf pxspeed>0 Then
	
		pxspeed=pxspeed-0.1
		
	EndIf
	

	If KeyDown(203) Then
		
		If pxspeed>-1.8 Then pxspeed=pxspeed-0.1
		
	Else
	
		If pxspeed<0 Then pxspeed=pxspeed+0.1
		
	EndIf
	
	px = x
	py = y

			
	;If pfalling = 1 Then
	
	;	If pyspeed<0.5 Then pyspeed = pyspeed + 0.01
				
	;Else
	
	;	pyspeed = 0
		
	;EndIf
	
	;py = py + pyspeed	
	

	Color 30,200,130
	Rect px,py,16,24
	Text px+30,py,pfalling

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function SaveMap()

	Color 20,20,75
	mapname$="mapdata.txt"

	Count = 0

	For t.tile = Each tile
	
		count = count + 1
		
	Next
	
		mapout = WriteFile(mapname$)
		
		WriteInt(mapout,count)
	
	For t.tile = Each tile
	
		WriteInt(mapout,t\xnum)
		WriteInt(mapout,t\ynum)
		WriteInt(mapout,t\mode)

	Next

	CloseFile mapout

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function LoadMap()

	Color 20,20,75
	whichmap$="mapdata.txt"
	For t.tile = Each tile
		
		Delete t
		
	Next

	mapin = ReadFile(whichmap$)
	count = ReadInt(mapin)
	
	For tile = 1 To count
	
		t.tile = New tile	
		t\xnum=ReadInt(mapin)
		t\ynum=ReadInt(mapin)
		t\mode=ReadInt(mapin)
		
	Next
		
	CloseFile(mapin)

End Function

Function ClearMap()

	For t.tile = Each tile
	
		Delete t
		
	Next

End Function


Edit: should I have put that in a codebox? :S


ingenium(Posted 2007) [#2]
This doesn't work 'cause you haven't load a new image for each tile you create!
Ex:
If Not KeyDown(58) Then
			
		t.tile = New tile
                ;LOOK here
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = x/16
		t\ynum = y/16 
		t\mode = tnumber
			
	Else
	
		;4x tile if CAPS pressed also
		t.tile = New tile
                ;LOOK here
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = x/16
		t\ynum = y/16 
		t\mode = tnumber
		
		t.tile = New tile
                ;LOOK here
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = (x/16)+1
		t\ynum = y/16 
		t\mode = tnumber
		
		t.tile = New tile
                ;LOOK here
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = x/16
		t\ynum = (y/16)+1
		t\mode = tnumber
		
		t.tile = New tile
                ;LOOK here
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = (x/16)+1
		t\ynum = (y/16)+1
		t\mode = tnumber
		
	EndIf
			
	



Then in the collision detection change to:
DrawImage t\img,t\xnum*16,t\ynum*16,t\mode
				
		If ImageRectOverlap(t\img,t\xnum*16,t\ynum*16,x,y,14,14) Then


Remember to change the type declaration!
Type tile
;img!!!
field img

;position within grid
Field xnum
Field ynum

;type of tile: ground, water or danger
Field mode

End Type




P.s. Obviously you have to add those modifications to the whole code! Remember to change the Loadmap() function for example!


elseano(Posted 2007) [#3]
Thanks Ingenium. I'll have a look.

edit:
Ok, I just tried that. Unfortunately, it makes loading the map so much slower. It actually just completely freezes for about 5 seconds before it loads :(

I then tried to use RectsOverlap to see if that made things any easier regarding collision, but I still have the same problem; it only detects a collision with the last tile created. Any ideas?


ingenium(Posted 2007) [#4]
This code should work.
Search for ">>>CORRECTED" to find any modifications!


;tiles test
;Sean Tomlin
;
;Last updated 13th June 07

;;;;;;;;;;;;;;;;;;;;;
;
;Space to save map
;Comma to load map
;Left mouseclick = place tile
;Delete + mouseclick = delete tiles
;Right mouseclick + move mouse = move around map
;Up/Down = change tile
;
;;;;;;;;;;;;;;;;;;;;;

Global tnumber = 0
Global maprx
Global mapry
Global maprmode

Global ox = 0
Global oy = 0

Global gravity# = 0.01

Graphics 640,480,16,1

SetBuffer BackBuffer()

ClsColor 134,156,175

;load tileset
Global tiles1=LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
MaskImage tiles1,255,0,255


Global px
Global py
Global pxspeed
Global pyspeed
Global pfalling=1

Global x
Global y

Global count
Global tilecount


;;;;;;;;;;;;;

While Not KeyHit(1)

	Cls
	
	Origin ox,oy
	
	UpdateMouse()
	
	If KeyHit(27) And tnumber<15 Then tnumber=tnumber+1
	If KeyHit(26) And tnumber>0 Then tnumber=tnumber-1
	
	If KeyHit(57) Then
	
		SaveMap()
		Text 10,290,"Save"
		
	EndIf
	
	
	If KeyHit(51) Then LoadMap()
	If KeyHit(14) Then ClearMap()

	UpdateTiles()	
	UpdatePlayer()
	
	Text 10,10,x/16
	Text 10,30,y/16
	
	Text 10,180,maprx
	Text 10,200,mapry
	Text 10,220,maprmode

	Flip
	
Wend

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Type tile

;>>>CORRECTED
Field img 

;position within grid
Field xnum
Field ynum

;type of tile: ground, water or danger
Field mode

End Type

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function UpdateMouse()
	
	;infiinite mouse movement
	xs=MouseXSpeed()
	ys=MouseYSpeed()
	MoveMouse 320,240
	
	;right mouse button (click + drag): move around map	
	If MouseDown(2) Then
		ox=ox+xs
		oy=oy+ys
	Else
		x=x+xs
		y=y+ys
	EndIf
	
	;draw the currently selected tile at mouse cursor
	DrawImage tiles1,x,y,tnumber
	
	Color 45,200,75
	Rect x,y,16,16,0
	
	;LMB: place tile
	If MouseDown(1) Then 
	
	If Not KeyDown(58) Then
			
		t.tile = New tile
                ;>>>CORRECTED
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
  		t\xnum = x/16
		t\ynum = y/16 
		t\mode = tnumber
			
	Else
	
		;4x tile if CAPS pressed also
		t.tile = New tile
                ;>>>CORRECTED
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = x/16
		t\ynum = y/16 
		t\mode = tnumber
		
		t.tile = New tile
                ;>>>CORRECTED
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = (x/16)+1
		t\ynum = y/16 
		t\mode = tnumber
		
		t.tile = New tile
                ;>>>CORRECTED
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = x/16
		t\ynum = (y/16)+1
		t\mode = tnumber
		
		t.tile = New tile
                ;>>>CORRECTED
                t\img = LoadAnimImage("C:/a/Co/Tiles/_A_TilesTest.bmp",16,16,0,16)
                MaskImage t\img,255,0,255
		t\xnum = (x/16)+1
		t\ynum = (y/16)+1
		t\mode = tnumber
		
	EndIf
			
	EndIf
	

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function UpdateTiles()

	For t.tile = Each tile
                ;>>>CORRECTED
		DrawImage t\img,t\xnum*16,t\ynum*16,t\mode
	        ;>>>CORRECTED	
		If ImageRectOverlap(t\img,t\xnum*16,t\ynum*16,x,y,14,14) Then
		
			If KeyDown(211) Then 
			
				Delete t
				
			Else 
			
		        EndIf

		        ;>>>CORRECTED
		        If ImageRectOverlap(t\img,t\xnum*16,t\ynum*16,px,py,16,26) Then
			
			pfalling = 0
		
		        Else
		
			pfalling = 1
			
		        EndIf
                 
	        ;>>>WHOA!!! YOU HAVE FORGOTTEN AN "EndIf"!!!
                EndIf
	Next

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function UpdatePlayer()

	If KeyDown(205) Then
		
		If pxspeed<1.8 Then pxspeed=pxspeed+0.1
		
	ElseIf pxspeed>0 Then
	
		pxspeed=pxspeed-0.1
		
	EndIf
	

	If KeyDown(203) Then
		
		If pxspeed>-1.8 Then pxspeed=pxspeed-0.1
		
	Else
	
		If pxspeed<0 Then pxspeed=pxspeed+0.1
		
	EndIf
	
	px = x
	py = y

			
	;If pfalling = 1 Then
	
	;	If pyspeed<0.5 Then pyspeed = pyspeed + 0.01
				
	;Else
	
	;	pyspeed = 0
		
	;EndIf
	
	;py = py + pyspeed	
	

	Color 30,200,130
	Rect px,py,16,24
	Text px+30,py,pfalling

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function SaveMap()

	Color 20,20,75
	mapname$="mapdata.txt"

	Count = 0

	For t.tile = Each tile
	
		count = count + 1
		
	Next
	
		mapout = WriteFile(mapname$)
		
		WriteInt(mapout,count)
	
	For t.tile = Each tile 
                ;>>>CORRECTED
	        writeInt(mapout,t\img)
		WriteInt(mapout,t\xnum)
		WriteInt(mapout,t\ynum)
		WriteInt(mapout,t\mode)

	Next

	CloseFile mapout

End Function

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function LoadMap()

	Color 20,20,75
	whichmap$="mapdata.txt"
	For t.tile = Each tile
		
		Delete t
		
	Next

	mapin = ReadFile(whichmap$)
	count = ReadInt(mapin)
	
	For tile = 1 To count
	
		t.tile = New tile
                ;>>>CORRECTED
                t\img=ReadInt(mapin)	
		t\xnum=ReadInt(mapin)
		t\ynum=ReadInt(mapin)
		t\mode=ReadInt(mapin)
		
	Next
		
	CloseFile(mapin)

End Function

Function ClearMap()

	For t.tile = Each tile
	
		Delete t
		
	Next

End Function



elseano(Posted 2007) [#5]
Thanks for the help, but I'm actually fairly certain now that it's nothing to do with the image and how it's handled. I wrote this to check. There are no images or external files involved so you should be able to run it and see for yourself: it STILL only recognises the last tile created! I really don't understand why...any other ideas?

Graphics 640,480,16,1

SetBuffer BackBuffer()

ClsColor 43,135,200


;;;;;;;;;;;;;;;

Type tile

;position within grid
Field xnum
Field ynum

;type of tile: ground, water or danger
Field mode

End Type

;;;;;;;;;;;;;;;;;


;;;;;;;;;;;;;;;;;;

Global px
Global py
Global pxspeed
Global pyspeed
Global pfalling=1

;;;;;;;;;;;;;;;;;;;

For i = 1 To 10

t.tile = New tile
t\xnum = 5+i
t\ynum = 8+i
t\mode = 0

Next

;;;;;;;;;;;;;;;;;;

While Not KeyHit(1)

	Cls
	
	UpdateTiles()
	
	Flip
	
Wend

End

;;;;;;;;;;;;;;;;


Function UpdateTiles()

	For t.tile = Each tile
                
		;DrawImage tiles1,t\xnum*16,t\ynum*16,t\mode
		
		Color 230,100,100
		Rect t\xnum*16,t\ynum*16,16,16,True
		
		If RectsOverlap(t\xnum*16,t\ynum*16,16,16,MouseX(),MouseY(),14,14) Then pfalling = 0 Else pfalling = 1
		
	Next
		
	Color 255,255,255
	Rect MouseX(),MouseY(),14,14,False
	Text 10,10,pfalling
	
	If pfalling = 0 Then 
	
		Color 255,0,0
		Oval 10,30,10,10
		
	EndIf
	
End Function




elseano(Posted 2007) [#6]
YES! Nevermind, I just figured it out. All that was needed was a "collided" true/false field in the "tile" type, which is set to true when there is a collision with the player, and false if not :)


big10p(Posted 2007) [#7]
Make this change:
	pfalling = 1
	For t.tile = Each tile
                
		;DrawImage tiles1,t\xnum*16,t\ynum*16,t\mode
		
		Color 230,100,100
		Rect t\xnum*16,t\ynum*16,16,16,True
		
		If RectsOverlap(t\xnum*16,t\ynum*16,16,16,MouseX(),MouseY(),14,14) Then pfalling = 0
		
	Next


P.S. Don't load the same animimage many times, as suggested by ingenium.