Collision problem

Blitz3D Forums/Blitz3D Beginners Area/Collision problem

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

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

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!

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?

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


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



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 :)

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.