Build a Platformer with Love2D

Collision Detection

25 min+50 XP

Collision Detection

Let's improve our collision detection to handle all sides of platforms, not just the top.

AABB Collision

We're using AABB (Axis-Aligned Bounding Box) collision - checking if two rectangles overlap:

lua
function checkCollision(a, b) return a.x < b.x + b.width and a.x + a.width > b.x and a.y < b.y + b.height and a.y + a.height > b.y end

Resolving Collisions

When a collision happens, we need to figure out which side was hit and push the player out:

lua
function love.load() player = { x = 50, y = 100, width = 30, height = 40, speed = 200, velocityY = 0, gravity = 800, jumpForce = -350, onGround = false } platforms = { {x = 0, y = 250, width = 400, height = 50}, {x = 100, y = 180, width = 80, height = 15}, {x = 220, y = 130, width = 100, height = 15}, {x = 50, y = 80, width = 70, height = 15}, } end function love.update(dt) -- Store previous position local prevX = player.x local prevY = player.y -- Horizontal movement if love.keyboard.isDown("left") or love.keyboard.isDown("a") then player.x = player.x - player.speed * dt end if love.keyboard.isDown("right") or love.keyboard.isDown("d") then player.x = player.x + player.speed * dt end -- Apply gravity player.velocityY = player.velocityY + player.gravity * dt player.y = player.y + player.velocityY * dt player.onGround = false -- Check collisions with platforms for i, plat in ipairs(platforms) do if checkCollision(player, plat) then -- Determine collision direction local overlapLeft = (player.x + player.width) - plat.x local overlapRight = (plat.x + plat.width) - player.x local overlapTop = (player.y + player.height) - plat.y local overlapBottom = (plat.y + plat.height) - player.y -- Find smallest overlap local minOverlap = math.min(overlapLeft, overlapRight, overlapTop, overlapBottom) if minOverlap == overlapTop and player.velocityY > 0 then -- Landing on top player.y = plat.y - player.height player.velocityY = 0 player.onGround = true elseif minOverlap == overlapBottom and player.velocityY < 0 then -- Hit head on bottom player.y = plat.y + plat.height player.velocityY = 0 elseif minOverlap == overlapLeft then -- Hit left side player.x = plat.x - player.width elseif minOverlap == overlapRight then -- Hit right side player.x = plat.x + plat.width end end end -- Screen boundaries if player.x < 0 then player.x = 0 end if player.x + player.width > 400 then player.x = 400 - player.width end if player.y < 0 then player.y = 0; player.velocityY = 0 end end function checkCollision(a, b) return a.x < b.x + b.width and a.x + a.width > b.x and a.y < b.y + b.height and a.y + a.height > b.y end function love.keypressed(key) if (key == "space" or key == "w" or key == "up") and player.onGround then player.velocityY = player.jumpForce end end function love.draw() love.graphics.setColor(0.4, 0.7, 1) love.graphics.rectangle("fill", 0, 0, 400, 300) love.graphics.setColor(0.4, 0.8, 0.4) for i, plat in ipairs(platforms) do love.graphics.rectangle("fill", plat.x, plat.y, plat.width, plat.height) end love.graphics.setColor(1, 0.3, 0.3) love.graphics.rectangle("fill", player.x, player.y, player.width, player.height) love.graphics.setColor(1, 1, 1) love.graphics.circle("fill", player.x + 10, player.y + 12, 5) love.graphics.circle("fill", player.x + 22, player.y + 12, 5) love.graphics.setColor(0, 0, 0) love.graphics.circle("fill", player.x + 12, player.y + 12, 2) love.graphics.circle("fill", player.x + 24, player.y + 12, 2) love.graphics.setColor(1, 1, 1) love.graphics.print("Full collision detection!", 10, 10) end

Try it! Notice how you can't pass through platforms from any direction now.

Ready to experiment?

Open the sandbox to modify and run the code yourself.