Tutorial – Getting started with Löve2D

Tired of the same old game frameworks?, lost among all those weird sounding game engines?, looking for a new and exciting tool to build your games with?

Look no further, you’ve come to the right place. Here at StrandedSoft we have good news for you, and those news are these:

What you need is love. Löve2D

Captura de pantalla 2015-03-09 a la(s) 21.17.30

Let’s build things!


Introducing Löve2D

Löve2D is a very straightforward 2D game framework. It’s completely free, open source and works on Linux, OS X and Windows. It uses Lua, and is a great tool for newbie game programmers as well as for the more experienced developers.

With it you can prototype ideas in a very short period of time, and you can also develop full featured games that will be able to be played by virtually anyone. It skips long and messy installation processes and get right to the point. It also features a set of handy developer resources, nice API docs and a thriving community behind it that will gladly help you out if needed.

Are these enough reasons yo get you interested already?, I hope so, because today we are going to give you a quick walkthrough through the process of creating a very simple 2D game with Löve2D. Let’s get to work!


Setting up

First, and easily enough, get your version of Löve2D and install it as described here. Installation is just a few clicks away and on some systems you can even go without even installing the thing. You just need your Löve2D executable from where you can launch your games.

With this done, let’s create our first game. Just create a new folder and name it whatever you feel like. Now, open up your favorite text editor and create two files, main.lua and conf.lua.
Inside conf.lua place the following:

This -as you probably have guessed by now – is our game configuration file. It sets up the game’s resolution, title and Löve2D version it needs to run.

Now, move onto main.lua and paste the following:

These are the 3 main methods that any game in Löve2D is composed of.

The first one, load(), is the place where you can preload anything you are going to use during gameplay. It gets called once right during the game’s boot up and allows you to do any “heavy” lifting and preparation you need for your game.

The second, update(), is where you set and update your game’s status on each frame. It’s only parameter is the delta time, which tells you how much time has passed since the last time the update method was called (in seconds). In here we will update the state of objects, check for collisions and update enemy AI, for example.

The last one, draw(), is simple. It gets called on every frame (after update) and draws whatever you want on screen. This means that for every object that you have on your game and that you want to appear on screen you must make sure that you draw it inside this method.

This may look simple, but this is all we need to make a game.

Now, to run your game you just need to do the following (it may sound weird, but bear with me for a second):

1.- select every file inside your game’s folder (for now it’s only main.lua and conf.lua) and compress them as a zip file (this depends largely on your OS, but is an easy task).

2.- once you have your .zip file, change its extension to .love

3.- Open your .love file with the Love application.

If everything went right you should see a motionless blue screen. If you want to exit the game just press ESC on your keyboard.


Got it?, good. Let’s keep going!


Building our little game

I’ve decided for a simple endless runner type of game, similar to the Wario hop minigame on Wario Land 4 and many others. We will have a small dude running infinitely and he will have to jump and dodge endless hordes of red blocks. More than enough to show you how easy and fast it is to set up a game with Löve2D 🙂

First, we are going to need some global variables to keep track of our game’s state and objects, so let’s declare them right above the load() method (yes, right at the top and out of any brackets). Like this:

Most of them are just control variables that are initialized to custom values. The rest represent sounds and font types, that will be used later during gameplay.

The most important one is the player object. As you can see it stores its position, jumping state, image and acceleration. You can create objects like this whenever you want and with as mane parameters as you want.

Also, note our obstacles array, which is initialized but is still empty.

Now, move onto the load() method and place the following inside:

In here, we initialize our player’s sprite, as well as the different sounds we are going to use during gameplay. We also create a custom font that will be used to display the jump counter and Game Over messages. Nothing really special.

With this done we can move to where the fun resides, the update() method. Punch in the following:

Ok, there are quite a few things in here. Let’s review them bit by bit.

First, we use a boolean isGameOver to check wether the game is lost or not, and while it isn’t we keep updating every object on screen, as well as checking for player input.

Next, we check if the player pressed the jump button, and if it was we set up our player jump state as true, which will enable the jumping acceleration to take effect on the player. Following this we apply a simple gravity force to the player, which will push it towards the ground and will stop acting as soon as the player lands. Notice how the gravity keeps getting stronger the longer the player falls, this means that the curve of the jump will be a bit more realistic and smoother, instead of following a linear acceleration scheme.

With this done, we just keep track of a timer that is decremented on every update() call, and when it reaches 0 we create a new obstacle on the right side of the screen, just about 25px farther away of the screen’s width.

Right afterwards we update every obstacle position on each frame, so they keep moving left until they are out of the screen. When they reach out the left border of the screen they are just removed from the array.

We use a simple boolean inside every obstacle to keep track of which ones were counted and which weren’t, so every time they get past the player we can update the point counter by 1.

Last, we check for collisions with the player, setting up the isGameOver variable to true when the player and any obstacle collide.

The checkCollision method is pretty straightforward, and just checks both objects bounding boxes. It looks like this:

Finally, we need to fill out our last -and quite important- method: draw().

Place the following inside:

As you can see, we build the floor and the sun with simple graphical primitives, filled with a specific color and with their own size. It is important to notice that every time your are going to use a color to paint any object you need to set the love.graphic object color value in order to be able to use it afterwards. The same happens with the text font when printing any message on screen.

Captura de pantalla 2015-03-09 a la(s) 22.26.45

Running under the sun

If you built everything right you should be able to run our game and play it. It’s not terribly hard and nothing that will keep you entertained for the rest of the day but it surely is a start. On top of that, the whole game isn’t even 150 lines of code long, which in my opinion speaks by itself on favor of this fun and exciting framework.

You can download the whole thing right here:



Wrap up

Löve2D is a very interesting and fun-to-use game framework. I hope this tutorial helps you out on getting up to speed with it and I’m sure lot’s of people will start building amazing things with it in the future. It’s the perfect match for game jams where there is no time to lose and lot’s of things to do, but it also is able to stand up proud among other better known frameworks.

On top of that, using it is great training for those of us who had never touched a single line of Lua code 😛

Thanks a lot for reading, see you soon!


Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.