Lua Academy · Lesson

Movement and Collisions

Make a playable scene.

Lesson 4 of 413 steps

Movement and Collisions is a free Lua Academy lesson on CoddyKit. This is lesson 4 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, and your progress syncs across the web and the CoddyKit app. The Lua Academy course includes 4 lessons in total.

Position and Velocity

Movement in LÖVE means changing an object's position over time. Store x and y, then add velocity in love.update scaled by dt.

Keeping velocity as dx and dy per second makes diagonal motion and physics clean and frame-rate independent.

function love.update(dt)
  player.x = player.x + player.dx * dt
  player.y = player.y + player.dy * dt
end

Input-Driven Movement

Combine polling with velocity to steer an object. Read direction keys in love.update and apply speed times dt.

Because love.keyboard.isDown is checked every frame, the player moves smoothly while the key is held.

function love.update(dt)
  if love.keyboard.isDown('left') then player.x = player.x - player.speed*dt end
  if love.keyboard.isDown('right') then player.x = player.x + player.speed*dt end
end

Normalizing Diagonal Speed

Pressing two direction keys at once makes diagonal motion faster, since both axes add full speed. To fix this, normalize the movement vector.

Divide the direction by its length so its magnitude is 1, then multiply by speed. Now diagonal travel matches straight-line travel.

local dx, dy = ix, iy
local len = math.sqrt(dx*dx + dy*dy)
if len > 0 then
  player.x = player.x + (dx/len) * player.speed * dt
end

Keeping Inside the Screen

Clamp position so objects stay on screen. Read the window size with love.graphics.getWidth and getHeight, then bound the coordinates.

math.max and math.min together clamp a value between a minimum and maximum cleanly.

local w = love.graphics.getWidth()
player.x = math.max(0, math.min(player.x, w - player.size))

Axis-Aligned Bounding Boxes

The simplest collision uses rectangles, called AABB for axis-aligned bounding boxes. Each object has x, y, width, and height.

Two boxes overlap when they intersect on both the horizontal and vertical axes at the same time. This check is fast and good enough for most 2D games.

-- box: { x, y, w, h }

The AABB Overlap Test

Two rectangles overlap when one's left edge is past the other's right edge on neither axis. The classic test combines four comparisons.

If all four are true, the boxes intersect. This single condition is the workhorse of 2D collision detection.

function overlaps(a, b)
  return a.x < b.x + b.w and
         b.x < a.x + a.w and
         a.y < b.y + b.h and
         b.y < a.y + a.h
end

Reacting to a Collision

Once overlaps returns true, decide what happens: pick up a coin, take damage, or stop movement. Check collisions in love.update after moving.

For pickups, simply remove the item or increment a score. For solid walls, you push the player back out.

function love.update(dt)
  movePlayer(dt)
  if overlaps(player, coin) then
    score = score + 1
    coin.dead = true
  end
end

Circle Collisions

For round objects, distance-based collision is more accurate. Two circles collide when the distance between centers is less than the sum of their radii.

Comparing squared distances avoids the costly square root, a common optimization when checking many objects.

function circlesHit(a, b)
  local dx, dy = a.x - b.x, a.y - b.y
  local rsum = a.r + b.r
  return dx*dx + dy*dy < rsum*rsum
end

Resolving Wall Collisions

To stop a player at a wall, a simple approach is to move on each axis separately and undo a step that causes overlap.

Move x, test; if it collides, revert x. Repeat for y. This axis-separated resolution prevents sticking on corners.

player.x = player.x + vx * dt
if overlaps(player, wall) then player.x = player.x - vx * dt end
player.y = player.y + vy * dt
if overlaps(player, wall) then player.y = player.y - vy * dt end

Applying Gravity

Platformers add constant downward acceleration. Increase vertical velocity by gravity times dt each frame, then apply velocity to position.

When the player lands on ground, zero out vertical velocity so they stop falling. Jumping sets a negative vertical velocity.

function love.update(dt)
  player.dy = player.dy + GRAVITY * dt
  player.y = player.y + player.dy * dt
end

Removing Dead Objects

After collisions you often remove objects. Iterate a list backward and call table.remove so indices stay valid while deleting.

Backward iteration is the safe Lua idiom for removing items mid-loop, avoiding skipped entries that forward iteration would cause.

for i = #coins, 1, -1 do
  if coins[i].dead then
    table.remove(coins, i)
  end
end

Quick Check

Test your understanding of movement and collisions in LÖVE.

Recap

Movement combines position, velocity, and dt, with normalization for fair diagonals and clamping to keep objects on screen. Collisions start with AABB overlap tests, with circle distance checks for round objects.

Resolve walls by reverting per-axis moves, add gravity for platformers, and remove dead objects by iterating backward with table.remove.

Free to start

Learn Lua with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
40
Lessons
159

Frequently Asked Questions

Is the “Movement and Collisions” lesson free?

Yes — any 3 lessons of the Lua Academy learning path, including “Movement and Collisions”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Lua Academy course includes 4 lessons in total.

What will I learn in “Movement and Collisions”?

Make a playable scene. You practise Lua Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Lua Academy?

No prior experience is required. Lua Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.

How long does the “Movement and Collisions” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Lua Academy lesson?

Yes. Every Lua Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The LOVE Game Loop
  2. Drawing Shapes and Images
  3. Handling Input
  4. Movement and Collisions
← Back to Lua Academy