Here I replace the ground with a list of rectangles. This code is dumb and not optimized. But I do the collision against rectangles in a different (but very clumsy here) way than someone posted in another thread. I prefer not to look at the player's movement to decide where to put him, instead I push the player out of a rectangle in the direction (left, right, up or down) that causes the smallest offset. This would function better when dealing with moving obstacles.
Code:
' Gravity.
' Constants used later to make code more readable.
constant LEFT = 1, RIGHT = 2, UP = 3, DOWN = 4
set window "Gravity", 256, 240, false, 3
set redraw off
' Player position.
playerX = 152
playerY = 0
' Size.
playerW = 16
playerH = 24
' Speed.
playerDX = 0
playerDY = 0
playerOnGround = false
' Obstacles. Each obstacle is represented by an array [x, y, width, height].
obstacles = [
[0, 0, 8, 240], ' Left wall.
[248, 0, 8, 240], ' Right wall.
[8, 224, 304, 16], ' Ground.
' Some blocks.
[100, 180, 32, 16],
[180, 140, 32, 8],
[16, 120, 100, 24],
[64, 60, 128, 8],
[8, 80, 16, 8]]
' Game loop, quit with escape key.
while not keydown(KEY_ESCAPE, true)
' Increase speed left/right on key left/right or decrease speed if left/right isn't pressed.
if keydown(KEY_LEFT) playerDX = max(playerDX - 0.1, -2)
elseif keydown(KEY_RIGHT) playerDX = min(playerDX + 0.1, 2)
elseif playerDX < 0 playerDX = min(playerDX + 0.2, 0)
elseif playerDX > 0 playerDX = max(playerDX - 0.2, 0)
' Is player on ground?
if playerOnGround
' Wants to jump?
if keydown(KEY_UP, true)
' Set players vertical speed to -4 and set playerOnGround to false.
playerDY = -3
playerOnGround = false
endif
else
' Increase vertical speed, this is gravity!
playerDY = playerDY + 0.1
endif
' Move player.
playerX = playerX + playerDX
playerY = playerY + playerDY
' Check for collision with obstacles.
playerOnGround = false ' This is only set to true if player stands on something.
foreach o in obstacles
' Do player and obstacle overlap?
if playerX + playerW > o[0] and playerX < o[0] + o[2] and
playerY + playerH > o[1] and playerY < o[1] + o[3]
' On which side of the obstacle do player and obstacle overlap the LEAST? Start with
' left side of obstacle. I'm pretty sure this could be done in a nicer way, but I'm
' running on fumes right now :D Also, lots of stuff above and below could be calculated
' ONCE.
minDir = LEFT
minDist = |o[0] - (playerX + playerW)|
' Right of obstacle?
dist = |o[0] + o[2] - playerX|
if dist < minDist
minDist = dist
minDir = RIGHT
endif
' Above obstacle?
dist = |o[1] - (playerY + playerH)|
if dist < minDist
minDist = dist
minDir = UP
endif
' Below obstacle?
dist = |o[1] + o[3] - playerY|
if dist < minDist
minDist = dist
minDir = DOWN
endif
' Move player to the side of the obstacle that requires the least movement.
if minDir = LEFT
playerX = o[0] - playerW
playerDX = 0
elseif minDir = RIGHT
playerX = o[0] + o[2]
playerDX = 0
elseif minDir = UP
' In this case player is standing on an obstacle, so set playerOnGround to true.
playerY = o[1] - playerH
playerDY = 0.05
playerOnGround = true
else
playerY = o[1] + o[3]
playerDY = 0
endif
endif
next
' Draw background.
set color 0, 0, 0
cls
' Obstacles.
set color 192, 128, 0
foreach o in obstacles draw rect o[0], o[1], o[2], o[3], true
' Player.
set color 255, 200, 0
draw rect playerX, playerY, playerW, playerH, true
' Some output.
set color 255, 255, 255
set caret 16, 2
if playerOnGround write "player on ground"
redraw
fwait 60
wend