Back

Activity 2.1: Your First LÖVE Window

divider

The Idea

LÖVE adds no Lua. Everything in Unit 1 is everything you need. What LÖVE adds is a window, a clock, a way to draw, and a way to read the keyboard — and it hands those to you through ordinary Lua functions you write.

Get it from love2d.org and install the version for your machine — on Windows, the 64-bit one unless you know otherwise. Expect your computer to try to stop you. Windows shows a blue "Windows protected your PC" box, and macOS says it cannot verify the developer. Neither means anything is wrong with the download, but ask your teacher rather than clicking through it on a school machine.

A game is a folder

Not a file. LÖVE looks for a folder containing a main.lua, and that is the whole requirement.

skynest/
main.lua

To run it, drag the folder onto the LÖVE application. That works everywhere and needs no setup. If you would rather use the terminal you can run love . from inside the folder, once LÖVE is on your path.

LÖVE calls you

This is the one genuinely new idea on the page, and it is worth slowing down for. In Unit 1 your file ran from top to bottom and finished. Here, LÖVE runs the loop and calls your functions. You do not call it, and you never write the loop.

main.lua
function love.load()
-- runs once, at the start
end
function love.update(dt)
-- runs every frame, before draw
end
function love.draw()
-- runs every frame, after update
end
  • love.load runs once. Set things up here.
  • love.update(dt) runs every frame — roughly sixty times a second. All your thinking goes here.
  • love.draw runs every frame too, straight after update. All your drawing goes here, and nothing else.

You do not have to define all three. A file with only love.draw is a valid game, which is where Task 1 starts.

Notice what these are. love is a table, and function love.draw() stores a function in it under the key draw. That is Activity 1.10 and Activity 1.7, and there is no framework magic in it — LÖVE checks whether that key holds a function and calls it if so.

Settings live in conf.lua

An optional second file next to main.lua, read before the window is made — which is why the window size cannot be set from love.load.

conf.lua
function love.conf(t)
t.window.width = 800
t.window.height = 600
t.window.title = "Skynest"
end

LÖVE fills t with every default first and then hands it to you, so you only override what you care about. The defaults are 800 by 600, not resizable.

One thing to expect from Activity 1.4

LÖVE runs an older Lua than the one you installed for Unit 1. Numbers print without the trailing .0, so 10 / 2 shows as 5 here. Two more consequences worth knowing now: // does not exist, so keep using math.floor; and math.random gives the identical sequence every run unless you seed it, exactly as Activity 1.4 warned.

Where the print output goes

print still works and is still your best debugging tool, but it writes to a terminal, not the window. Launch from a terminal and you will see it. To put text in the window you need love.graphics.print, which is a different function and belongs in love.draw.

divider

Build

Make a folder called skynest. Everything in Unit 2 goes in it, and you will keep adding to the same project all the way to the end.


Task 1: The smallest possible game

  • Create main.lua in that folder with nothing but a love.draw.
  • Print some text at 20, 20.
  • Drag the folder onto LÖVE. A window should open with your text in the top-left corner.
main.lua
-- main.lua
function love.draw()
love.graphics.print("Skynest online", 20, 20)
end

Task 2: Prove the loop is running

  • Add a frames counter as a local at the top of the file.
  • Add love.update and increase it by one each frame.
  • Draw the count under your text, and add a dark background.
  • The number should climb fast — about 60 per second. That is the loop, and you never wrote it.
main.lua
-- main.lua
local frames = 0
function love.load()
love.graphics.setBackgroundColor(0.05, 0.05, 0.1)
end
function love.update(dt)
frames = frames + 1
end
function love.draw()
love.graphics.print("Skynest online", 20, 20)
love.graphics.print("Frames drawn: " .. frames, 20, 40)
end

Task 3: Set up the window

  • Add a conf.lua beside main.lua — a second file, not a change to the first.
  • Set the width, height, and title.
  • Run it again. The title bar should change, which is how you know LÖVE found the file.
  • Then deliberately misspell love.conf as love.config and run once more. No error — you just silently get the defaults, because LÖVE looked up a key that was not there. Activity 1.10 explains why that is not a special case.
conf.lua
-- conf.lua
function love.conf(t)
t.window.width = 800
t.window.height = 600
t.window.title = "Skynest"
end

Challenge (Optional)

  • Track elapsed seconds instead of frames by adding dt rather than 1, and print it with string.format to one decimal place. The next two activities are built on the difference between those two numbers.
  • Add print(frames) inside update, launch from a terminal, and watch it scroll. Then take it out again.
  • Set t.window.resizable = true and drag the window edge. Note that your text stays put — Activity 2.2 covers why, and what to do about it.
divider

Check Your Work

The Skynest window showing two lines of text and a frame counter

Two lines of text and a counter climbing by about sixty a second. That is the whole of Activity 2.1.

There is no terminal output to compare from here on, so from now on these sections show you the window instead. What you should have:

  • An 800 by 600 window titled Skynest.
  • A very dark background rather than LÖVE's default.
  • Two lines of text in the top-left corner.
  • A frame count climbing by roughly 60 each second.

If the window opens but is blank, your drawing is probably in love.update. If nothing opens at all, LÖVE could not find main.lua — check that you dragged the folder and not the file.