Flaky maze collision detection

BlitzPlus Forums/BlitzPlus Beginners Area/Flaky maze collision detection

Hi again all.

Sorry about the huge post, but I think this is difficult to explain.
I have managed to get a little further in my endeavours, but yet again have hit a wall. I am now able to display my map, and my tank sprite (32x32 image) moves around it. I have (attempted) placed in some collision detection code along the lines of:

I declared some temporary local variables to hold the players position then when the player presses a key, we use the following code to see if the player is moving to a position that = 1 which means a wall, so the player cant move there

If maze(Px/WallWidth,Py/WallHeight) = 1 Then
Px = Tempx
Py = Tempy
EndIf

Problem is, this works, Sometimes!. I'm thinking it has something to do with the precision required to move around, maybe someone can throw me a clue as to help with moving around the maze a little eaiser while we are at it.

Anyway, here is the code I have for now, its starting to get pretty big (well for me and coding anyway...). I will probably change things later to use TYPES, but for now I dont know enuff about TYPES, so I will look into that later.

not sure if this helps, but here are the 2 sprite images I created for this game: My Tanks Sprites

Basically I am after help with (but not neccesarily source hints, even putting me on the right track improving my algorithm or pseudocode will be useful :-)

1. Fixing the collision detection issues I have.
2. Making it easier to move around the maze, its too precise at the moment.
3. I want to have several game levels, and have added about 5, but havent a clue as to how to read these into my ReadMaze function since I dont know how to pass a variable to the Restore function. It tried Restore PlayerLevel, but it spat the dummy coz the levels are called Level1, Level2 etc.

Any tips would be appreciated.
; Tank Maze Game
; 10 Nov - Started work.
; 10 Nov - managed to display the maze!
; 11 Nov - Created all the sprites
; 11 Nov - added movement - sprite now moves around - no collision detection
; 12 Nov - had a crack at tank/wall collision detection.  Almost works.
;	     - Problem is the player needs to be too precise when turning
;		 - Left or right.  need to find a way where the player only needs
;		 - to be close, but not exactly a division of 32 (wallwidth or wallheight)
; 12 Nov - Tried to get rid of most magic numbers.
; 12 Nov - Firing code implemented.  Bullets change direction when player
;        - changes direction.  Guess I need to fix that :-)

 
; TO BE ADDED
;		 1 - See if the TYPES I have created are ok and will work as they are
; 		 2 - Add the other bad guys 
;		 3 - Give the bad guys some basic AI -start with pacman type AI.
;		 4 - Draw explosion graphics
;		 5 - Add bullet firing code
;		 6 - Add bullet moving code
;		 7 - Add sound effects
;		 8 - Add music track(s)
;		 9 - Add a title screen
;		10 - Add a menu screen


;*********** GRAPHICS INITIALISATION **********
Graphics 800,600,32,2
SetBuffer BackBuffer()


;*********** VARIABLE DECLARATION **********
Global MapWidth=16					; Width of the maze in tiles
Global MapHeight=16					; Heidht of the maze in tiles
Global MinXPos = 32					; minimum X position player can be
Global MaxXPos = 448				; Max X Position player can be
Global MinYPos = 32					; Minimum Y position player can be
Global MaxYPos = 448				; Maximum Y postioon player can be
Global PLevel = 1					; Players starting level
Global PDirection = 1				; 1 = N, 2=E, 3=S, 4=W
Global Px = 1						; Players Starting X position
Global Py = 1						; Players Starting Y position
Global PlayerSpeed = 3					; Player Speed
Global SpriteWidth = 32				; Width of players sprite
Global SpriteHeight = 32			; Height of players sprite
Global MaxSpriteFrames = 4
Global WallWidth = 32				; Width of wall sprite
Global WallHeight = 32				; Height of wall sprite
Global BulletSpeed = 6				; Speed Player bullets move
Dim maze(MapWidth-1,MapHeight-1)  	; The whole map


;*********** KEYBOARD SCANCODES **********
Const KArrowUp    = 200  			; Move player forward
Const KArrowDown  = 208  			; Reverse Player 
Const KArrowLeft  = 203  			; Turn Player sprite left
Const KArrowRight = 205  			; Turn Player sprite right
Const KSpace = 57		  			; Player Fires a Bullet

;*********** LOAD GRAPHICS **********
Global gfxWall = LoadImage("Albg1.bmp") ; 32x32 wall tile
Global gfxPlayer = LoadAnimImage("player1frames.bmp",SpriteWidth,SpriteHeight,0,MaxSpriteFrames)
Global gfxPBullet = LoadImage("p1shot.bmp")

;*********** IMAGE MASKS (TRANSPARENCY) **********
MaskImage gfxPlayer,255,0,255
MaskImage gfxPBullet,255,0,255

;*********** TYPE DECLARACTIONS **********
Type BulletType
	Field x
	Field y
End Type

Global Bullet.BulletType

; Read in all data statements into variables
ReadMaze()							; Read maze data into maze()() variable


;********** MAIN GAME LOOP **********
While Not KeyHit(1)
	; clear the screen
	Cls
	DrawMaze()
	DrawImage gfxPlayer,Px,Py,PDirection
	MovePlayer()
	Flip
Wend
End



;******************************
;*     READ MAZE FUNCTION     *
;* Reads the data statements  *
;*  to load the maze data     *
;* into the maze()() variable *
;******************************
Function ReadMaze()
	; Read (load) in the maze data into a variable
	Restore Level1
	For y = 0 To MapHeight-1
		For x = 0 To MapWidth-1
			Read maze(x,y); get the map data and store into value
		Next ; x
	Next ; y
End Function


;******************************
;*     DRAW MAZE FUNCTION     *
;*    Draws the mini maze     *
;******************************
Function DrawMaze()
	For y=0 To MapHeight-1
		For x=0 To MapWidth-1
			If maze(x,y) ; no '=something' means it's not equal to 0, so "IF bla=1 then" equals "IF bla then" equals "IF bla"
				DrawImage gfxWall,x*WallWidth,y*WallHeight
			EndIf
		Next
	Next
End Function


;******************************
;*   MOVE PLAYER FUNCTION     *
;* Moves player forward or    *
;*  backward, turn left or    *
;* turn right depending on    *
;* the key the player presses *
;******************************
Function MovePlayer()
	; Need to check player isnt moving into a wall.
	Local Tempx = Px
	Local Tempy = Py
	; if player presses KArrowLeft - Turn player left (anticlockwise)
	If KeyDown(KArrowLeft) Then
		PDirection = 3
				Px = Px - PlayerSpeed
		; turn player and move in direction and move them

	EndIf
	; if player presses KArrowRight - Turn player right (clockwise) and move them
	If KeyDown(KArrowRight) Then
		PDirection = 1
			Px = Px + PlayerSpeed
	EndIf
	; if player presses KArrowDown - Turns the player around 180 deg and moves them down
	If KeyDown(KArrowDown) Then
		PDirection = 2
			Py = Py + PlayerSpeed
	EndIf
	; if player presses KArrowUp - turns and moves the player up the screen
	If KeyDown(KArrowUp) Then
		PDirection = 0
			Py = Py - PlayerSpeed
	EndIf
	; Fire button
	If KeyDown(KSpace) Then
		ShootBullet(Px,Py)
	EndIf
	
	; Move the players bullet
	MoveBullet()
	
	; Limit the players movement within the maze only
	If Px < MinXPos Then Px = MinXPos
	If Px > MaxXPos Then Px = MaxXPos
	If Py < MinYPos Then Py = MinYPos
	If Py > MaxYPos Then Py = MaxYPos
	; see if player is colliding with a wall.
	; if so, put the player back into the old position
	If maze(Px/WallWidth,Py/WallHeight) = 1 Then
		Px = Tempx
		Py = Tempy
	EndIf
End Function


Function ShootBullet(Bulletx,Bullety)
	; create a new instance of a bullet
	Bullet.BulletType = New BulletType
	Bullet\x = Bulletx
	Bullet\y = Bullety
	
End Function


Function MoveBullet()
	For Bullet.BulletType = Each BulletType
		; remove bullet if it leaves the screen
;		If Bullet\x < 0 Then
;			Delete Bullet
;		EndIf
;		If Bullet\x > MaxXPos Then
;			Delete Bullet
;		EndIf
;		If Bullet\y < MinYPos Then
;			Delete Bullet
;		EndIf
;		If Bullet\y > MaxYPos Then
;			Delete Bullet
;		EndIf
		If PDirection = 0 Then ; Player moving up
			Bullet\y = Bullet\y - BulletSpeed
			DrawImage GfxPBullet,Bullet\x+(SpriteWidth/2)-3,Bullet\y+(SpriteHeight/2)-16
		EndIf
		If PDirection = 1 Then ; Player moving right
			Bullet\x = Bullet\x + BulletSpeed
			DrawImage GfxPBullet,Bullet\x+(SpriteWidth/2)+10,Bullet\y+(SpriteHeight/2)-3
		EndIf
		If PDirection = 2 Then ; Player moving down
			Bullet\y = Bullet\y + BulletSpeed
			DrawImage GfxPBullet,Bullet\x+(SpriteWidth/2)-3,Bullet\y+(SpriteHeight/2)+10
		EndIf
		If PDirection = 3 Then ; Player moving left
			Bullet\x = Bullet\x - BulletSpeed
			DrawImage GfxPBullet,Bullet\x+(SpriteWidth/2)-16,Bullet\y+(SpriteHeight/2)-3
		EndIf
	Next
End Function


;****************** DATA ******************

.Level1
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,1,0,1,1,0,0,1,1,0,1,1,0,1
Data 1,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1
Data 1,0,0,0,0,1,0,1,1,0,1,0,0,0,0,1
Data 1,0,1,1,0,0,0,0,0,0,0,0,1,1,0,1
Data 1,0,0,0,0,1,1,0,1,1,1,0,0,0,0,1
Data 1,0,1,1,0,0,1,0,1,0,0,0,1,1,0,1
Data 1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,1
Data 1,0,1,0,1,0,1,1,0,1,1,0,0,1,0,1
Data 1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1
Data 1,0,0,0,0,0,1,0,1,0,1,1,0,0,0,1
Data 1,0,1,0,0,0,1,0,1,0,0,0,0,1,0,1
Data 1,0,1,1,0,1,1,0,1,0,1,0,1,1,0,1
Data 1,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

.Level2
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,1,0,0,0,1,0,0,0,0,1,1,0,1
Data 1,0,1,0,0,0,0,1,0,0,0,0,0,1,0,1
Data 1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,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,1
Data 1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1
Data 1,0,1,1,1,1,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,1
Data 1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1
Data 1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1
Data 1,0,1,0,0,0,0,0,1,0,0,0,0,1,0,1
Data 1,0,1,1,0,0,0,0,1,0,0,0,1,1,0,1
Data 1,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

.Level3
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,1,0,0,0,0,0,0,0,0,1,1,0,1
Data 1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1
Data 1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1
Data 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
Data 1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1
Data 1,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,1
Data 1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1
Data 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
Data 1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1
Data 1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1
Data 1,0,1,1,0,0,0,0,0,0,0,0,1,1,0,1
Data 1,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

.Level4
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,1,0,1,1,1,1,1,1,0,1,1,0,1
Data 1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,0,0,1,1,0,0,1,1,0,0,1,0,1
Data 1,0,1,0,0,1,1,0,0,1,1,0,0,1,0,1
Data 1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1
Data 1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1
Data 1,0,1,0,0,1,1,0,0,1,1,0,0,1,0,1
Data 1,0,1,0,0,1,1,0,0,1,1,0,0,1,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1
Data 1,0,1,1,0,1,1,1,1,1,1,0,1,1,0,1
Data 1,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

.Level5
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,1,0,0,0,1,1,0,0,0,1,1,0,1
Data 1,0,1,0,0,0,1,1,1,1,0,0,0,1,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,1,1,1,0,0,0,0,1,1,1,1,0,1
Data 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
Data 1,0,1,1,0,0,0,0,0,0,0,0,1,1,0,1
Data 1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1
Data 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
Data 1,0,1,1,1,1,0,0,0,0,1,1,1,1,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,1,0,0,0,1,1,1,1,0,0,0,1,0,1
Data 1,0,1,1,0,0,0,1,1,0,0,0,1,1,0,1
Data 1,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


quite simple: you only checked the top-left coordinate right now, meaning that you can drive downwards into a wall until the TOP pixel hits it.. ofcourse you need to check all 4 corners of the tank! And if you eventually have smaller objects, then you might even have to check in-between coordinates as well..

Additionally: if you have a closed map you don't need to check the map-boundaries with:

If Px < MinXPos Then Px = MinXPos
If Px > MaxXPos Then Px = MaxXPos
If Py < MinYPos Then Py = MinYPos
If Py > MaxYPos Then Py = MaxYPos

Naturally, you need to set the initial tank-coordinate to 32,32 then..

This boundaries-checking caused the tank to react properly at the edges of the map and weird in the rest of the map. Things like that *can* cause fuss, therefor it's best to use the actual map as edge, and a real screen coordinate.. (what if your wallwidth/height changes? you need to setup values all again then!).