# Introduction guide to LÖVE the 2D game engine

> I will keep updating this guide from your feedback and the continuation of my exploration of LÖVE. Last update on October, 6th 2022.

Recently I decided to spend a bit of time exploring LÖVE on my spare time. It uses Lua as programming language. And is an open-source engine available for free on Windows, Mac, and Linux. You can also build your game for iOS/Android and even Web.

Website: [https://love2d.org/](https://love2d.org/)

I thought it would be easy coming from Unity and different others 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](https://www.lua.org/pil/contents.html)
    
* Package manager for Lua: **LuaRocks** [https://luarocks.org/](https://luarocks.org/)
    

### Variables

```swift
local x = 1 -- Only available in local scope
globalVar = 2 -- Global variable
```

### Usual Operations

```swift
-- 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 `i++` in Lua to increment.

### If, elseif, else

```swift
if playerJumped then 
  -- Start jump animation
elseif playerCrouch then 
  -- Start crouch animation
else
  -- Play idle animation
end
```

### For Loops

```swift
-- Loop over i from 0 to 20 and increment by 1 at each cycle 
for i = 0,20,1
do
  -- Do something
end
```

**Note**: you cannot have multiple variables in the for statement. If you need multiple variables look at doing a `while` loop instead.

### While Loops

```swift
local i = 0
while i < 20
do 
  -- Do something 
  i = i + 1
end
```

### Functions

```swift
function f(argument1) 
  return something * argument1
end
```

**Note**: all the primary types (numbers, boolean, nil, strings) are passed by values, everything else is passed by reference to the function.

### Anonymous Functions

#### Inline argument

```swift
do(function()
    print("Hello!")
end)
```

#### Variable

```swift
myfunc = function(n)
    return n*n
end

-- example of call
myfunc(5)

-- example of use as argument
do(myfunc)
```

### Classes and OOP

There is a native way of doing it, using the official language reference: [https://www.lua.org/pil/16.1.html](https://www.lua.org/pil/16.1.html)

But I found a bit inelegantly and the function `setmetadatatable` is confusing.

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](https://gist.github.com/paulmoore/1429475)

You only need to import the file `classes.lua` in your project, but definitely look the examples.

But here is a quick example.

```swift
-- 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 `new` to instantiate and define `init` in the class, which is called implicitly during the `new` operation.
    
* 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](https://www.lua.org/pil/11.4.html)

```swift
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 `list.lua` in your project. Then you can use that way:

```swift
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 specific type in Lua, it’s a bit like arrays in PHP which can be associative or indexed.

```swift
-- 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](https://github.com/kikito/cron.lua)

```swift
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](https://love2d.org/wiki/Main_Page)
    

### Structure

To run a game you need a folder with a `main.lua` at least.

Example of minimal structure:

```swift
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
```

**Note**: There are others functions you may need you can find the details here: [https://love2d.org/wiki/love](https://love2d.org/wiki/love)

### IDE

I advice you to use Visual Code with the extension [https://marketplace.visualstudio.com/items?itemName=SK83RJOSH.love-launcher](https://marketplace.visualstudio.com/items?itemName=SK83RJOSH.love-launcher)

Also add a file `conf.lua` at the root of your folder, with that contents:

```swift
function love.conf(t)
	t.console = true
end
```

Now each time you press `Alt+L`, your game will pop plus the console window which can help to debug.

### Manipulate the Game Window

You can change the default window display attribute during load of your game. Example:

```swift
function love.load()
    love.window.setMode(800, 600, {resizable=true, minwidth=400, minheight=300})
end
```

**Details**: [https://love2d.org/wiki/love.window.setMode](https://love2d.org/wiki/love.window.setMode)

### SVG Files

I found a nice package that add supports of SVG files to LÖVE. It is called TÖVE.

**Details**: [https://github.com/poke1024/tove2d](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 framerate, it’s not possible natively.

But I found that gist from Leandros: [https://gist.github.com/Leandros/98624b9b9d9d26df18c4](https://gist.github.com/Leandros/98624b9b9d9d26df18c4) that just does the job perfectly.

You need to copy/paste the code at the end of your [main.l](http://main.ly)ua and that’s it. Constant 60FPS.

You can tweak the FPS if you need.

### ECS (Entity Component System)

LÖVE is not natively using the paradigm [ECS](%5Bhttps://en.wikipedia.org/wiki/Entity_component_system%5D(https://en.wikipedia.org/wiki/Entity_component_system)). But if you like ECS like I do, I found a tiny ECS framework for it. It was written in 2016, pretty old already, but it’s that tiny that it did age well.

Here is the link about: [https://github.com/bakpakin/tiny-ecs](https://github.com/bakpakin/tiny-ecs)

If you want to use it there’s only one file `tiny.lua` to copy to your project.

You can find a project using it here as example: [https://github.com/bakpakin/CommandoKibbles](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](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 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](https://love2d.org/forums/viewtopic.php?p=193765#p193765)

```swift
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: https://love2d.org/wiki/Game\_Distribution

### More details on WegGL

First, you need to install the tool from Davidobot: [https://github.com/Davidobot/love.js](https://github.com/Davidobot/love.js)

```bash
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`:

```swift
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 browser, I realize also I needed to edit the file `/etc/nginx/mime.types` to add the definition for wasm file:

```swift
    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, it includes a `tar` command line utility that you can use to make zip in scripts. But it looks like it’s not supported by the WebGL build. So I switched to 7Zip using the following parameters:

![Untitled.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1665027812714/ekWI08TXe.png align="left")

You can also use 7zip in command line.

**Example of build & deploy script**

```bash
#!/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 getting 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 about the possibilities of LÖVE.
