Lua + LÖVE: Make a Game · Lesson 01 · 25 min
Launch your first LÖVE game
Install LÖVE, run a game folder, and understand the three callbacks at the heart of a 2D game.
How Lua and LÖVE divide the work.
A window that draws your first game object.
Move that object by changing two numbers.
You are going to build Orbit Runner, a small arcade game about collecting gold signals while dodging meteors. It uses only colored shapes and generated sound, so you can learn the engine without hunting for assets.
By the end of the course, you will be able to:
- read and write practical Lua;
- reason about a real-time game loop;
- handle input, movement, spawning, collision, state, sound, and saving;
- organize a LÖVE project into modules; and
- package the finished game as a
.lovefile.
No programming background is assumed. Type the code rather than pasting it whenever you can—the small mistakes you fix are part of learning the language.
The two-layer mental model
Lua is the programming language. It gives you values, variables, functions, conditions, loops, and tables.
LÖVE (often written Love2D) is the game framework hosting that Lua code. It opens the window, reads the keyboard, draws shapes and images, plays audio, and calls your functions at the right times.
Your game is not a script that runs top to bottom and exits. It stays alive because LÖVE repeatedly calls functions you define:
function love.load()
-- Run once, at startup.
end
function love.update(dt)
-- Change the game state every frame.
end
function love.draw()
-- Draw the current state every frame.
end
These specially named functions are callbacks. You define them; LÖVE decides when to call them.
The most useful habit in this course is to keep state, update, and draw distinct. A position is state. Changing the position belongs in update. Showing it belongs in draw.
Install the stable version
This course targets LÖVE 11.5, the current stable release. LÖVE 12.0 is still in development as this course is written. Download 11.5 from the official LÖVE site, install it, and verify the command if your installer adds it to your path:
love --version
You should see a version beginning with LOVE 11.5. If your terminal cannot find love, the installation may still be fine:
- Windows: drag a game folder onto
love.exe, or add LÖVE’s install directory toPATH. - macOS: run
open -n -a love .from inside a game folder, or invoke/Applications/love.app/Contents/MacOS/lovedirectly. - Linux: install the
lovepackage supplied by your distribution, then runlove ..
You need a plain-text code editor. Any editor with Lua syntax highlighting is enough.
Make the game folder
Create this exact structure somewhere convenient:
The filename matters. A LÖVE game must have main.lua at the top level of its folder or archive.
Put this in main.lua:
local playerX = 480
local playerY = 270
function love.load()
love.window.setMode(960, 540)
love.window.setTitle("Orbit Runner")
love.graphics.setBackgroundColor(0.04, 0.03, 0.08)
end
function love.draw()
love.graphics.setColor(0.33, 0.91, 0.84)
love.graphics.circle("fill", playerX, playerY, 18)
end
Run the folder, not the file:
love orbit-runner
If your terminal is already inside orbit-runner, use:
love .
You should see a dark 960 × 540 window with a cyan circle in the center.
Read the program like the computer
The two local lines create state:
local playerX = 480
local playerY = 270
love.load runs once. It configures the window and background.
love.draw runs many times per second. Each time, it chooses a color and draws a filled circle. In LÖVE 11.x, color channels range from 0 to 1: 0 means none of that channel; 1 means full intensity.
The screen origin (0, 0) is at the top-left. x grows to the right and y grows downward:
(0, 0) ───────────────► +x
│
│ (480, 270)
│
▼
+y
Function arguments go between parentheses. This call has four:
love.graphics.circle("fill", playerX, playerY, 18)
-- mode center x center y radius
Make it yours
Change one thing at a time, save, then relaunch the game.
- Move the circle 100 pixels to the right.
- Move it near the upper-left without letting it leave the screen.
- Change it to gold: try
love.graphics.setColor(1, 0.83, 0.47). - Change
"fill"to"line".
Checkpoint
You are done when you can predict where the circle will appear before running the game, and you can explain why love.load and love.draw do different jobs.
When it does not run
Read LÖVE’s error screen from the top. It normally gives a filename, line number, and message. Check these first:
- Is the file named exactly
main.lua, notmain.lua.txt? - Are paired characters closed:
" ",( ), andend? - Did you run the folder containing
main.lua? - Did you write
lovein lowercase?
The error screen is not a verdict. It is the engine telling you where its understanding stopped.
Next, you will learn enough Lua to control what happens inside these callbacks.