Install Love2D, understand the game loop, handle input, draw sprites, detect collisions, and ship a playable .love file — all in one session.
Love2D (stylized as LÖVE) is a free, open-source 2D game framework for Lua. It wraps SDL2 and OpenGL, giving you a window, audio, input, and a 60fps game loop — all from Lua scripts. Install it from love2d.org, then run any game with love /path/to/your/game/.
love.load() runs once at startup, love.update(dt) runs every frame with the elapsed time in seconds, love.draw() renders the frame. Everything else is optional.-- main.lua — every Love2D game starts here
function love.load()
-- Called once at startup
-- Initialize all your game state here
love.window.setTitle("My Game")
love.window.setMode(800, 600, {resizable=false, vsync=true})
end
function love.update(dt)
-- Called every frame; dt = seconds since last frame (usually ~0.016)
-- Update positions, physics, AI, timers here
end
function love.draw()
-- Called after update; render everything here
-- Love2D clears the screen before each draw call
love.graphics.setColor(1, 1, 1) -- white (RGBA, 0-1 range)
love.graphics.print("Hello, Love2D!", 10, 10)
end
function love.keypressed(key)
-- Called once when a key is first pressed
if key == "escape" then love.event.quit() end
end
-- main.lua — player controlled with arrow keys or WASD
local player = {}
local SPEED = 200 -- pixels per second
function love.load()
love.window.setMode(800, 600)
player = {
x = 400,
y = 300,
w = 40,
h = 40,
color = {0.2, 0.6, 1}, -- blue
}
end
function love.update(dt)
local dx, dy = 0, 0
if love.keyboard.isDown("left", "a") then dx = -1 end
if love.keyboard.isDown("right", "d") then dx = 1 end
if love.keyboard.isDown("up", "w") then dy = -1 end
if love.keyboard.isDown("down", "s") then dy = 1 end
-- Normalize diagonal movement
if dx ~= 0 and dy ~= 0 then
local len = math.sqrt(dx*dx + dy*dy)
dx, dy = dx/len, dy/len
end
player.x = player.x + dx * SPEED * dt
player.y = player.y + dy * SPEED * dt
-- Clamp to screen bounds
local W, H = love.graphics.getDimensions()
player.x = math.max(0, math.min(W - player.w, player.x))
player.y = math.max(0, math.min(H - player.h, player.y))
end
function love.draw()
love.graphics.setColor(player.color)
love.graphics.rectangle("fill", player.x, player.y, player.w, player.h)
-- HUD
love.graphics.setColor(1, 1, 1)
love.graphics.print(string.format("x=%.0f y=%.0f", player.x, player.y), 8, 8)
love.graphics.print(love.timer.getFPS() .. " FPS", 740, 8)
end
function love.keypressed(key)
if key == "escape" then love.event.quit() end
end
Axis-Aligned Bounding Box (AABB) collision is the simplest form: two rectangles overlap if neither is fully to the left, right, above, or below the other.
-- AABB collision helper
local function aabb(a, b)
return a.x < b.x + b.w
and a.x + a.w > b.x
and a.y < b.y + b.h
and a.y + a.h > b.y
end
-- Enemy factory
local function make_enemy(x, y)
return {
x = x, y = y,
w = 32, h = 32,
vx = math.random(-120, 120),
vy = math.random(-80, 80),
alive = true,
}
end
local enemies = {}
local score = 0
function love.load()
love.window.setMode(800, 600)
math.randomseed(os.time())
for i = 1, 8 do
table.insert(enemies, make_enemy(
math.random(50, 750),
math.random(50, 550)
))
end
-- (assume player table from previous example)
end
function love.update(dt)
local W, H = love.graphics.getDimensions()
-- Move and bounce enemies
for _, e in ipairs(enemies) do
if e.alive then
e.x = e.x + e.vx * dt
e.y = e.y + e.vy * dt
if e.x < 0 or e.x + e.w > W then e.vx = -e.vx end
if e.y < 0 or e.y + e.h > H then e.vy = -e.vy end
-- Check collision with player
if aabb(player, e) then
e.alive = false
score = score + 10
end
end
end
-- (player movement code from above goes here too)
end
function love.draw()
-- Player
love.graphics.setColor(0.2, 0.6, 1)
love.graphics.rectangle("fill", player.x, player.y, player.w, player.h)
-- Enemies
for _, e in ipairs(enemies) do
if e.alive then
love.graphics.setColor(1, 0.3, 0.3)
love.graphics.rectangle("fill", e.x, e.y, e.w, e.h)
end
end
-- Score
love.graphics.setColor(1, 1, 1)
love.graphics.print("Score: " .. score, 8, 8)
end
# A .love file is just a ZIP with main.lua at the root cd /path/to/your/game zip -9 -r mygame.love . # Run it directly love mygame.love # On macOS — bundle into an .app (distribute standalone) # Download the Love2D macOS .app, then: cp mygame.love "love.app/Contents/Resources/mygame.love" # Rename love.app to mygame.app and distribute # Linux AppImage or Windows EXE: see love2d.org/wiki/Game_Distribution
update(dt) and draw() methods. Your love.update just calls current_state:update(dt)..love file and run it from the command line to verify it works standalone.Add a state machine to your mini-game with three states: menu, playing, and gameover. Each state should have its own update, draw, and keypressed handlers. The menu shows the high score. The gameover screen shows the score and lets the player restart. Persist the high score to a file using love.filesystem.write.
The foundations from today carry directly into Day 5. In the next session the focus shifts to Day 5 — building directly on everything covered here.
Before moving on, verify you can answer these without looking:
Live Bootcamp
Learn this in person — 2 days, 5 cities
Thu–Fri sessions in Denver, Los Angeles, New York, Chicago, and Dallas. $1,490 per seat. June–October 2026.
Reserve Your Seat →