Platform Collision

BlitzPlus Forums/BlitzPlus Programming/Platform Collision

weebo(Posted 2007) [#1]
Hello,

I'm using BlitzPlus to get the hang of the basic mechanics behind a platform game.

My problem is with the collision detection between the player sprite and the floor.

The play area is 640x480, divided in to tiles of 8x8, and the player sprite is 15x16 pixels. (x,y)

The code I have used checks all of the tiles around the player at any given time. Using this information it knows if the player should be falling, walking on the floor etc

This is all great, however, I'm finding that the player sprite doesn't always land flush with the floor tile. Sometimes the player lands pixel perfectly on the top of the floor, other times the players feet dip a few pixels below and overlap in to the floor.

Can anybody throw some light on it for me?

Cheers!


*******Code now follows**********

AppTitle "Little Platformer"

;Player Variables
Global frmplayer, tmrplayer ;player animation
Global playerx, playery, jumping ;player position/status
Global ladderpresent ;is the player on a ladder
Global tileleft
Global tileright
Global tileabove
Dim tilebelow(1)
Dim tileon(1)

;Player constants
playerx=250 ;start position
playery=455


;Environment Variables
Global gravity#,yspeed#

;Environment Constants
gravity =.3;Affects jump
jump#= -5 ;jump height
speedx#=0 ;ground friction

;Level variables
Dim level(79,59)


;MAIN PROGRAM;
;************;


;Prepare Screen
Graphics 640,480,16,1 ;set resolution

;load player animation and mask
gfxplayer=LoadAnimImage("c:\dk\player.bmp",15,16,0,12)
MaskImage gfxplayer,255,0,255

;load level gfx
floorgfx=LoadImage("C:\dk\floor.bmp")
MaskImage floorgfx,255,0,255
laddergfx=LoadImage("C:\dk\ladder.bmp")
MaskImage laddergfx,255,0,255

;Load the current level from file to the array
filein = ReadFile("c:\dk\levels\level1.txt")
For y = 0 To 59
For x = 0 To 79
level(x,y) = ReadByte(filein) ;read 1 byte at a time
Next
Next
CloseFile(filein)


;MAIN GAME LOOP;
;**************;

While Not KeyDown(1) ;until esc is pressed

SetBuffer BackBuffer()
Cls

;draw the level/objects on screen
;Floor tiles
For y = 0 To 59
For x = 0 To 79

Select level(x,y)
Case 49
DrawImage floorgfx,x*8,y*8
Case 50
DrawImage laddergfx,x*8,y*8
End Select
Next
Next

;draw the player
DrawImage gfxplayer,playerx,playery,frmplayer

;discover players immediate surroundings
tilebelow(0) = level(playerx/8,(playery/8)+2)
tilebelow(1) = level((playerx/8)+1,(playery/8)+2)
tileabove = level(playerx/8,(playery/8)-1)
tileleft = level((playerx/8)-2,playery/8)
tileright = level((playerx/8)+2,playery/8)
tileon(0) = level(playerx/8,playery/8)
tileon(1) = level(playerx/8+1,playery/8)


;check collisions against surroundings
If tileon(0) = 49 Or tileon(1) = 49 And yspeed <= 0 Then ;stop jumping you have hit your head
yspeed=0
End If

If tileon(0) = 50 Or tileon(1) = 50 Then ;player is over a ladder
ladderpresent=1
Else
ladderpresent=0
End If

If tilebelow(0) = 49 Or tilebelow(1) = 49 And yspeed >=0 Then ;stop if you are falling and land on a tile
jumping = 0
yspeed=0
End If

If tilebelow(0) = 48 And tilebelow(1) = 48 Then ;falling if nothing is below
jumping=1
End If

;check player input and update accordingly
If JoyX()=-1 Then ;left
;friction
speedx = speedx -.2
If speedx < -2 Then speedx = -2

If MilliSecs() > tmrplayer + 100 Then
tmrplayer=MilliSecs() ; 'reset' the timer
frmplayer=( frmplayer + 1 ) Mod 3 ; increment the frame, flip to 0 if we are out
End If
EndIf

If JoyX()=+1 Then ;right
speedx = speedx +.2
If speedx > 2 Then speedx=2

If MilliSecs() > tmrplayer + 100 Then
tmrplayer=MilliSecs() ; 'reset' the timer
frmplayer=3+( frmplayer + 1 ) Mod 3; increment the frame, flip to 0 if we are out
End If

EndIf

If JoyY()=-1 And ladderpresent=1 Then ;up if a ladder is present
playery=playery-1 ;only go up if there is more ladder
If MilliSecs() > tmrplayer + 100 Then
tmrplayer=MilliSecs() ; 'reset' the timer
If frmplayer=8 Then
frmplayer=10
Else
frmplayer=8
EndIf

End If
EndIf

If JoyY()=+1 And ladderpresent=1 Then ;down if a ladder is present

playery=playery+1 ;only go down if there is more ladder to go down
If MilliSecs() > tmrplayer + 100 Then
tmrplayer=MilliSecs() ; 'reset' the timer
If frmplayer=8 Then
frmplayer=10
Else
frmplayer=8
EndIf
End If
EndIf

If JoyHit(1) And jumping=0 Then ;jump if not already
jumping = 1 ;the player is mid-jump
yspeed# = jump#
EndIf

If jumping=1 ; check that we have pushed the jump key
YSpeed# = YSpeed# + Gravity# ; this will calculate the y location in pixels
If yspeed# > 4 Then yspeed# = 4
playery = playery + YSpeed ; this will add our calculated number to our current y position
End If

;updates on player variables
speedx = speedx * .88 ;friction
playerx = playerx + speedx ;update player x position

;debugging
;Show tilesbelow
;Rect(playerx,playery+16,8,8,0)
;Rect(playerx+8,playery+16,8,8,0)

;show tileon
;Rect(playerx,playery,8,8,0)
;Rect(playerx+8,playery,8,8,0)

Flip ;draw the screen

Wend


b32(Posted 2007) [#2]
First, move the line where you draw the player:
DrawImage gfxplayer,playerx,playery;,frmplayer

Before the line:
If JoyY()=-1 And ladderpresent=1 Then ;up if a ladder is present

So that the player is drawn right after checking the collisions.

In this collision code, there are two parts that stop the jumping with "yspeed = 0"
Before that line, insert:
playery=playery / 8 * 8

This will place the player back on a whole tile again after a jump.

In your main loop, you are setting the buffer, "SetBuffer BackBuffer()" I don't know if it matters much, but it can be moved before the loop.


weebo(Posted 2007) [#3]
b32, thank you for taking the time to check this for me. The line "playery=playery / 8 * 8" was exactly what I needed. What can I say...it was late!

I've also moved the setbuffer line out of the main loop as it's not required as you mention.

Many thanks!
Neil