Getting Started with LOVE 2D
LOVE (also written as LÖVE or LOVE2D) is a free, open-source framework for building 2D games using Lua. It’s a fantastic starting point if you want to create games without dealing with complex engine setups. Think of it like a toy box full of building blocks specifically designed for making games.
What Is LOVE 2D?
LOVE is a game engine. An engine handles the boring but necessary stuff: opening a window, drawing graphics, detecting key presses, playing sounds. Instead of building these from scratch, you tell LOVE what you want and it handles the rest.
Here’s why people like LOVE:
- Lightweight — The entire engine is just a few megabytes
- Cross-platform — Your games run on Windows, macOS, and Linux
- Lua-based — You write games in Lua, which is one of the easiest programming languages to learn
- Free and open — No cost, no license worries, and you can see how it works under the hood
Installing LOVE 2D
The installation process depends on your operating system.
Windows
- Go to love2d.org and download the latest installer
- Run the installer (choose 32-bit or 64-bit — if you’re unsure, 64-bit is probably right for modern computers)
- Optional: Add LOVE to your system PATH so you can run it from any command prompt
To check if it worked, open Command Prompt and type:
love
If you see a window pop up with the LOVE launcher, you’re all set.
macOS
You have two options:
Option 1: DMG file
- Download the
.dmgfile from love2d.org - Drag the LOVE app into your Applications folder
Option 2: Homebrew If you use Homebrew, run:
brew install love
To verify, open Terminal and type love. You should see the launcher window.
Linux
The exact command depends on your distribution:
Debian or Ubuntu:
sudo apt install love
Fedora:
sudo dnf install love
Arch Linux:
sudo pacman -S love
If you’re on a different distribution, check your package manager for the love package. Some distributions only package older versions, so you might need to download the AppImage from love2d.org instead.
Run love in your terminal to verify the installation.
Your First LOVE 2D Game
Now let’s write some game code.
File Structure
LOVE expects your main game file to be called main.lua. That’s it. No complex folder structure, no configuration files needed. Just one file to start.
Create a new folder for your project, then create a file inside called main.lua:
mygame/
└── main.lua
The Game Loop
Every LOVE game has three main functions that form what we call the “game loop” — the heartbeat of your game that runs continuously while the game is running.
Think of these functions like a play in a theater:
love.load()— The preparation before the play starts (runs once)love.update()— What happens on stage during each moment of the play (every frame)love.draw()— Taking a photograph of the stage (every frame)
Here’s what each one does:
-- main.lua
-- love.load runs once when your game starts
-- Use it to set up your initial game state
function love.load()
-- x and y store the position of our square
x = 400
y = 300
end
-- love.update runs every frame (typically 60 times per second)
-- This is where you update game logic like movement
-- dt stands for "delta time" - the seconds since the last frame
function love.update(dt)
-- Move the square 100 pixels to the right every second
-- Multiplying by dt ensures consistent speed regardless of frame rate
x = x + 100 * dt
end
-- love.draw runs every frame after update
-- This is where you put all your rendering code
function love.draw()
-- Draw a red filled rectangle
-- Arguments: mode, x, y, width, height
-- Note: x and y are the TOP-LEFT corner of the rectangle
-- We're offsetting by 25 to center the 50x50 square on our position
love.graphics.setColor(1, 0, 0) -- RGB values from 0 to 1
love.graphics.rectangle("fill", x - 25, y - 25, 50, 50)
end
Why does dt matter? Imagine two computers: one is slow and runs your game at 30 frames per second, another is fast and runs it at 60 frames per second. Without dt, the fast computer would move objects twice as fast. By multiplying movement by dt, both computers move objects at the same speed — the slow one just takes more frames to get there.
The Coordinate System
Before we go further, it’s important to understand LOVE’s coordinate system. The origin point (0, 0) is at the top-left corner of the window. Positive X extends to the right, and positive Y extends downward. This is different from some other engines where Y goes upward.
When you draw shapes, the x and y coordinates you provide determine where they’re positioned based on this system.
Creating a Window
By default, LOVE creates a window that’s 800 pixels wide and 600 pixels tall. You might want something different, so let’s see how to customize it.
The recommended way is to create a separate file called conf.lua:
-- conf.lua
function love.conf(t)
-- t is a table that holds all configuration options
t.window.title = "My First Game" -- Window title
t.window.width = 1024 -- Width in pixels
t.window.height = 768 -- Height in pixels
t.window.resizable = true -- Let user resize the window
t.window.fullscreen = false -- Start in windowed mode
t.window.vsync = true -- Sync with monitor refresh rate
end
You can also set the window size in code using love.window.setMode:
function love.load()
-- Arguments: width, height, and optional settings table
love.window.setMode(1024, 768, {
fullscreen = false,
resizable = true,
vsync = true
})
end
Use conf.lua when you want configuration that’s set before the game starts. Use love.window.setMode() when you need to change settings dynamically during gameplay.
Drawing Shapes
Let’s draw some shapes. LOVE provides several functions in the love.graphics module:
function love.draw()
-- Draw a filled rectangle
-- "fill" means solid, "line" would be just the outline
love.graphics.rectangle("fill", 100, 100, 200, 150)
-- Draw an outlined rectangle
love.graphics.rectangle("line", 100, 100, 200, 150)
-- Draw a filled circle
-- Arguments: x, y, radius, segments (higher = smoother circle)
love.graphics.circle("fill", 400, 300, 50, 32)
-- Draw an outlined circle
love.graphics.circle("line", 400, 300, 50, 32)
-- Draw a line between two points
love.graphics.line(0, 0, 800, 600)
-- Draw a triangle (polygon with 3 sides)
-- Pass a table of x,y coordinates for each vertex
love.graphics.polygon("fill", {
500, 200, -- vertex 1 (x, y)
600, 350, -- vertex 2 (x, y)
500, 350 -- vertex 3 (x, y)
})
-- Set color before drawing (RGB + optional Alpha)
-- All values range from 0 to 1
love.graphics.setColor(0.2, 0.5, 0.8, 1) -- light blue
end
The color function uses values from 0 to 1 instead of the more common 0-255. Think of it like this: 0 means “none of this color” and 1 means “maximum of this color”. So (1, 0, 0) is pure red, (0, 1, 0) is pure green, (0, 0, 1) is pure blue, and (1, 1, 1) is white.
Handling Keyboard Input
Now let’s make your game interactive. LOVE provides several ways to detect key presses.
The simplest is love.keyboard.isDown(), which checks if a key is currently held down:
function love.update(dt)
local speed = 200 * dt
-- Check if arrow keys are held down
if love.keyboard.isDown("left") then
x = x - speed
end
if love.keyboard.isDown("right") then
x = x + speed
end
if love.keyboard.isDown("up") then
y = y - speed
end
if love.keyboard.isDown("down") then
y = y + speed
end
end
For detecting individual key presses (like firing once when a key is pressed), use the love.keypressed callback:
function love.keypressed(key)
if key == "escape" then
-- Quit the game when escape is pressed
love.event.quit()
end
if key == "space" then
-- Do something when space is pressed
print("Space pressed!")
end
end
Loading Images
Games need graphics beyond just shapes. Here’s how you load and display images:
function love.load()
-- Load an image from a file
-- Make sure you have a "player.png" in your game folder
playerImage = love.graphics.newImage("player.png")
x = 400
y = 300
end
function love.draw()
-- Draw the image at position x, y
-- The third argument is rotation in radians
love.graphics.draw(playerImage, x, y, 0)
-- You can also specify the origin point (center of the image)
-- love.graphics.draw(playerImage, x, y, 0, 1, 1, playerImage:getWidth() / 2, playerImage:getHeight() / 2)
end
Place your image files in the same folder as your main.lua. LOVE will automatically find them.
Running Your Game
Run your game:
love /path/to/your/game/folder
For example, if your game is in a folder called “mygame” on your desktop on Windows:
love C:\Users\YourName\Desktop\mygame
You can also run LOVE on a .zip file containing your game files — LOVE will automatically find and run the main.lua inside.
Common Setup Problems
Let’s cover some issues that often trip up beginners.
Wrong Filename
Problem: Nothing happens when you run LOVE
Solution: Check that your entry point is exactly main.lua (lowercase, with the .lua extension). LOVE won’t find files named Main.lua, main.LUA, or anything else.
Working Directory Issues
Problem: You get errors about missing files, or assets don’t load
Solution: Always run LOVE from your game folder, not from somewhere else. The simplest way is to navigate to your game folder first, then run love . (the dot means “current folder”).
Frame-Rate Dependent Movement
Problem: Your game runs faster on faster computers
Solution: Always multiply movement by dt in your love.update function:
-- This runs at different speeds on different computers
x = x + 5
-- This runs at the same speed everywhere
x = x + 200 * dt
Drawing Outside love.draw
Problem: Graphics don’t appear, or they flicker wildly
Solution: LOVE only draws what you put inside the love.draw() function. If you try to draw elsewhere, it either won’t show up or will behave unpredictably. Keep all rendering code in love.draw().
Version Information
The current stable version of LOVE is 11.x (nicknamed “Mysterious Mysteries”). It supports Lua versions 5.1, 5.2, 5.3, and 5.4, depending on which version of LOVE you use.
You can check what version you’re running in code:
function love.load()
local v = love.getVersion()
print(string.format("LOVE version: %d.%d.%d", v.major, v.minor, v.revision))
-- Prints something like "LOVE version: 11.5.0"
end
Where to Go Next
Now that you’ve got LOVE running, here are some great next steps:
- love.graphics documentation — Check out love2d.org/wiki/love.graphics for all drawing functions
- love.keyboard documentation — Learn to detect key presses at love2d.org/wiki/love.keyboard
- love.mouse documentation — Handle mouse input at love2d.org/wiki/love.mouse
- love.audio documentation — Add sound to your games at love2d.org/wiki/love.audio
- Official tutorials — The LOVE wiki has excellent tutorials at love2d.org/wiki/Tutorial:Callback_Functions
See Also
- love2d.org — Official website and downloads
- LOVE Wiki — Complete function reference
- Lua 5.4 Reference Manual — Learn Lua fundamentals
- love.graphics API — Drawing functions reference