Recently, I decided to spend a bit of time exploring LÖVE in my spare time. It uses Lua as programming language. Also, it’s an open-source engine available for free on Windows, Mac, and Linux. You can also build your game for iOS/Android and even WebGL. Website: https://love2d.org/ I thought it would be easy, coming from Unity and different other languages. But it took me a bit of time to find the information or logic behind the language and engine. So I decided to write this guide to help you get kick-started and easily transitioned to LÖVE. Guide Lua Language Here are some examples of different things you may want to use: Important Links Programming language reference: Programming in Lua https://www.lua.org/pil/contents.html Package manager for Lua: LuaRocks https://luarocks.org/ Variables local x = 1 -- Only available in local scope globalVar = 2 -- Global variable Usual Operations -- increment variable i = i + 1 -- decrement variable i = i - 1 -- concatenate the variable name with two strings message = "Hello, my name is "..name.."!" -- not equal operator (others are the same as others languages) test = something ~= 0 -- logical operatiors: not, and, or test1 = not something test2 = something and somethingelse test3 = something or somethingelse -- tertiary operator (a ? b : c) test = a and b or c Note: there is no in Lua to increment. i++ If, elseif, else if playerJumped then -- Start jump animation elseif playerCrouch then -- Start crouch animation else -- Play idle animation end For Loops -- Loop over i from 0 to 20 and increment by 1 at each cycle for i = 0,20,1 do -- Do something end : you cannot have multiple variables in the for statement. If you need multiple variables look at doing a loop instead. Note while While Loops local i = 0 while i < 20 do -- Do something i = i + 1 end Functions function f(argument1) return something * argument1 end : all the primary types (numbers, boolean, nil, strings) are passed by values, everything else is passed by reference to the function. Note Classes and OOP There is a native way of doing it, using the official language reference: https://www.lua.org/pil/16.1.html But I found it a bit inelegantly and the function is confusing. setmetadatatable So I found another solution that simplifies the code you need to write to create classes and child classes: https://gist.github.com/paulmoore/1429475 You only need to import the file in your project, but definitely look at the examples. classes.lua But here is a quick example. -- Load the classes helper file local classes = require "classes" local Enemy = classes.class() -- Create a class without any parent Enemy.count = 0 function Enemy:init(name) self.hp = 100 self.name = name Enemy.count = Enemy.count + 1 end -- static function function Enemy.count() return Enemy.count end local Orc = classes.class(Enemy) -- Create an Orc who is an enemy function Orc:init(name, weapon) self.super:init(name) -- call to parent constructor self.weapon = weapon end -- Instantiate some orcs local orcWithAxe = Orc.new("Zotor", "Axe") local orcWithBow = Orc.new("Plead", "Bow") Notes: We use to instantiate and define in the class, which is called implicitly during the operation. new init new For static methods and variables, use the class name followed by a then the name of the element you want to access. . For object methods and attributes, use the variable name followed by a then the name of the element you want to access. : For private methods, don’t prefix the name of the function with the name of the class. Queues and Stacks For that, I made a module based on the example provided by the official language reference. https://www.lua.org/pil/11.4.html List = {} function List.new () return {first = 0, last = -1} end function List.count(l) return #table end function List.pushleft (list, value) local first = list.first - 1 list.first = first list[first] = value end function List.pushright (list, value) local last = list.last + 1 list.last = last list[last] = value end function List.popleft (list) local first = list.first if first > list.last then error("list is empty") end local value = list[first] list[first] = nil -- to allow garbage collection list.first = first + 1 return value end function List.popright (list) local last = list.last if list.first > last then error("list is empty") end local value = list[last] list[last] = nil -- to allow garbage collection list.last = last - 1 return value end return List Copy that in a file in your project. Then you can use it this way: list.lua queue = List.new() stack = List.new() -- Enqueue values List.pushright(queue, someValue) List.pushright(queue, someValue) List.pushright(queue, someValue) -- Stack values List.pushleft(stack, someValue) List.pushleft(stack, someValue) List.pushleft(stack, someValue) -- Consume queue (FIFO) local value1 = List.popleft(queue) local value2 = List.popleft(queue) -- Consume stack (LIFO) local value3 = List.popleft(stack) local value4 = List.popleft(stack) Arrays and Tables (structured data) Table is a specific type in Lua, it’s a bit like arrays in PHP, which can be associative or indexed. -- same initialization local array = {} local table = {} -- initializing array values for i = 0,20,1 do array[i] = i end -- initialization table values table["x"] = 0 table["y"] = 0 -- or could be done at the declaration local coords = {x=0, y=0} Cron If you want to schedule a specific action at a certain time, you want to use cron/timer. The easiest solution I found is to use the tool made by kikito: https://github.com/kikito/cron.lua local cron = require 'cron' local function printMessage() print('Hello') end -- the following calls are equivalent: local c1 = cron.after(5, printMessage) local c2 = cron.after(5, print, 'Hello') c1:update(2) -- will print nothing, the action is not done yet c1:update(5) -- will print 'Hello' once c1:reset() -- reset the counter to 0 -- prints 'hey' 5 times and then prints 'hello' while not c1:update(1) do print('hey') end -- Create a periodical clock: local c3 = cron.every(10, printMessage) c3:update(5) -- nothing (total time: 5) c3:update(4) -- nothing (total time: 9) c3:update(12) -- prints 'Hello' twice (total time is now 21) LÖVE Engine Specifics OK, Lua itself requires some learning, as you’ve seen. But LÖVE too! Important Links Official documentation: LÖVE Wiki https://love2d.org/wiki/Main_Page Structure To run a game, you need a folder with at least a file . main.lua Example of minimal structure: function love.load() -- Run once at game initialization end function love.keypressed(key, scancode, isrepeat) -- Run each time a key on the keyboard is pressed end function love.mousepressed(x, y, button, istouch, presses) -- Run each time a mouse button is pressed, supports multi-touch too end function love.update(dt) -- Run at each frame before drawing it -- This is where you handle most of your game logic end function love.draw() -- Called at every frame to draw the game end : There are other functions you may need, you can find the details here: Note https://love2d.org/wiki/love IDE I advise you to use Visual Code with the extension https://marketplace.visualstudio.com/items?itemName=SK83RJOSH.love-launcher Also, add a file at the root of your folder, with the contents: conf.lua function love.conf(t) t.console = true end Now each time you press , your game will pop plus the console window which can help to debug. Alt+L Manipulate the Game Window You can change the default window display attribute during the loading of your game. Example: function love.load() love.window.setMode(800, 600, {resizable=true, minwidth=400, minheight=300}) end : Details https://love2d.org/wiki/love.window.setMode SVG Files I found a nice package that adds support for SVG files to LÖVE. It is called TÖVE. : Details https://github.com/poke1024/tove2d No active development since a couple of years ago, so be aware of that. But for me, it worked fine. Fixed Update If you want to make your game at a constant frame rate, it’s not possible natively. But I found that gist from Leandros: that just does the job perfectly. https://gist.github.com/Leandros/98624b9b9d9d26df18c4 You need to copy/paste the code at the end of your ua and that’s it. Constant 60FPS. main.l You can tweak the FPS if you need. ECS (Entity Component System) LÖVE is not natively using the paradigm . But if you like ECS as I do, I found a tiny ECS framework for it. It was written in 2016, pretty old already, but it’s so tiny that it did age well. ECS Here is the link: https://github.com/bakpakin/tiny-ecs If you want to use it, there’s only one file to copy to your project. tiny.lua You can find a project using it here as an example: https://github.com/bakpakin/CommandoKibbles Post Processing Screen VFX If you want to have some post-processing screen virtual effects, the easiest I found is to use moonshine: https://github.com/vrld/moonshine It contains 16 effects like glow, vignette, crt, ... That you can chain as you want and change parameters on the fly. If you want to create your own effect, you will have to start to write shaders and extend moonshine effects. Check the GitHub README to understand how to use it. Screen Shake Effect I found on the forum of LÖVE a reply from vrld that does the job: https://love2d.org/forums/viewtopic.php?p=193765#p193765 local t, shakeDuration, shakeMagnitude = 0, -1, 0 function startShake(duration, magnitude) t, shakeDuration, shakeMagnitude = 0, duration or 1, magnitude or 5 end function love.update(dt) if t < shakeDuration then t = t + dt end end function love.draw() if t < shakeDuration then local dx = love.math.random(-shakeMagnitude, shakeMagnitude) local dy = love.math.random(-shakeMagnitude, shakeMagnitude) love.graphics.translate(dx, dy) end end Game distribution If you want to distribute your game, your starting point is the wiki at that address: love2d.org/wiki/Game_Distribution More details on WegGL First, you need to install the tool from Davidobot: https://github.com/Davidobot/love.js npm install -g love.js Web server with proper headers Then you will need a server and a web server running on it. On my end, I use Nginx, and this is how I configured my : location location /beathoven/ { add_header Cross-Origin-Opener-Policy same-origin; add_header Cross-Origin-Embedder-Policy require-corp; alias /usr/share/nginx/html/beathoven/; } Add missing mime type After several tries looking at errors in the browser, I realize also I needed to edit the file to add the definition for wasm file: /etc/nginx/mime.types application/vnd.google-earth.kmz kmz; application/wasm wasm; application/x-7z-compressed 7z; Use 7zip not tar on Windows To package your game into a love file, you need to simply zip the files. And since Windows 10, Windows includes a command line utility that you can use to make zip. But it looks like it’s not supported by the WebGL build. So I switched to 7Zip using the following parameters: tar You can also use 7zip in the command line. Example of building & deploy script #!/bin/bash tools/7za a -tzip Beathoven.zip assets/ gameobjects/ pages/ responsive/ utils/ fonts.lua main.lua -mx0 mv Beathoven.zip Beathoven.love love.js -t Beathoven -c Beathoven.love game ssh server rm -rf /usr/share/nginx/html/beathoven/* scp -r game/* server:/usr/share/nginx/html/beathoven/ Conclusion Obviously, I haven’t covered everything here, but I hope that it can give a nice introduction to help you get quickly productive with LÖVE and create some cool games! Next week I’ll share about a Rhythm game called Beathoven I decided to make while exploring the possibilities of LÖVE. Originally published . here