You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In this tutorial, you will learn how to easily set up a development environment that will allow you to start learning and coding right away,
with multiple helpful features that will make it easier, and the material you will start with will be making simple games using the Love2D framework.
Unlike most tutorials on the internet, I'm not going to focus on grinding down basic programming concepts and practices into you,
instead, each lesson, I will show you how to do a new thing, and try to give you a couple of additional tasks, and ideas for extending
the code I present to you.
At the end of each article, I will also add additional reference materials containing
useful or interesting info explaining terms and concepts used in the article, and more.
I will bold the terms used in the article if they are in the reference.
If you have any questions or suggestions, you can reach me at "com Asmageddon gmail" (well, not exactly that, but I have faith you can figure it out)
Introduction and setup:
2.1. Installing Love2D:
Love2D, also known as LÖVE is a framework that can be used for making 2D games, it's well documented, easy to use, and powerful while remaining simple.
Linux: Your package manager probably contains Love2D in its repository, you probably know how to use it, but if not, here is how you do it on Debian/Ubuntu/Linux Mint, you can do sudo aptitude install love inside the terminal.
Another note: This tutorial series has been written for LÖVE 0.9.0.
2.2. Installing ZeroBrane Studio IDE:
ZeroBrane is a simple IDE for the Lua programming language, which is what we will be coding in.
You should go for the stable version, but if you want to, or need, you can get the development version.
To do so, press the "Download ZIP" button, unzip the file into a directory,
and then run zbstudio.exe if you are on Windows, or zbstudio.sh if you're on OS X or Linux.
On Linux you might need to set the file's permissions so it can be executed.
Note: .love files are simply renamed zip archives containing Lua code using Love that Love2D can execute like apps,
you can create them yourself, and you can see what is inside them by renaming them to .zip files and simply unpacking them.
3.2. Projects, and ZeroBrane examples
ZeroBrane(ZBS for short) has a simple project system, where you open a folder as a project. By default, a folder with example projects is openened.
Note: If you downloaded the development version, you can download them from
their github page, the same way you did in step 2.2 - download the zip, and unpck it into a folder
To run the the Love2D samples, you will need to change the current project to their respective directories.
First, click the ... button on the project panel on the left.
After that, enter the love2d-samples folder and then one of its subfolders(hello, shooter, trajectory), press open.
Change the current interpreter to Love2D, by using the main menu->Project->Lua Interpreter->Love2d option.
To launch the project, press F5 for debug mode, or F6 for run mode. You can also use Project->Run/Start Debugging to achieve the same effect. The hotbar also has a green triangle that launches the project in debug mode.
If you launched the game in debug mode, it will pause after creating the window. You will need to resume it with the hotbar button. This is an example of a debugging feature, where your program is paused and you can inspect its state, but that will be left for a future lesson.
If you want to see the code for the games, the project panel to the left contains
You can also double click the main.lua file in the project panel on the left, to see the source code of the example.
If you don't understand anything yet, that's fine, it's what this tutorial series is for.
3.3. Unpack a .love file and load it as a project
Note: This is an optional task, you don't have to do it.
As mentioned in task #1, .love files are simply renamed .zip files, that you can both create and unpack easily.
The specific process depends on what operating system you're using.
On OS X: Right click the file to rename it, change the .love extension to .zip, and unpack it by double clicking, contents will be put in a new folder automatically.
On Windows: 7zip allows you to unpack .zip archives even if they're renamed, which means you can just right click the .love file and choose 7-Zip->Extract To. Don't extract into the current folder, because there is often a lot of files inside.
On Linux: Most file managers have a built-in unarchiving feature, with some you might need to change the file extension from .love to .zip, in others you don't. Make sure to create a new folder to unpack the files into.
On Linux using the command line: Just enter the folder in which your file is located using cd and then unpack it with unzip <filename> -d <folder to unpack into>
Afterwards, in ZBS, click the ... button on the project panel, and navigate to the folder you have unpacked the contents of the file to, open it.
Conversely, to create a .love file, just zip the contents of your project's directory(.love files must always contain a main.lua file)
and change the extension to .love. You won't need to do this in order to run your projects, but you will need it if you want to distribute them.
Feel free to look around the code if you want, then continue on to the next tutorial.
Epilogue:
You got all the necessary tools installed, and if you ever want to send someone something you created,
or take a look at source code of any .love fil, you know how to. With that, you're ready to go to the next tutorial.
Next article: No link yet
Reference:
5.1. Terms:
Framework - A piece of software providing generic functionality that can be used to develop certain kind or kinds of products on top of it, like a house is built on a foundation.
IDE - Integrated Development Environment, a program, or set of programs that offer all kinds of tools useful in programming as a single package. They usually offer functionality such as a source code editor, a debugger(a tool used to fix bugs(problems), and abstract away a lot of details, allowing you to focus on your work without worrying about unnecessary details
Lua - A simple and minimalistic programming language.
Programming language - An artificial language, created for the purpose of allowing humans to write computer programs in a simple way.
Source code - Instructions for the computer in human-readable form, it's what you write to create programs.
Debugging - The process of finding, and fixing bugs(errors and incorrect behaviors) in your code.
Debugger - A program that assists in debugging, most full-features IDEs will allow you to use one or more of such tools very easily.
5.2. Useful links:
Wikipedia - Always an invaluable resource, if you want to read up on a topic and understand its basics.
Google - If you have a problem, google it. Chances are someone solved it before you and you can find a solution within minutes.
Tutorial 2: Writing code, basic structure of Love2D games.
Overview:
In the second tutorial in this series, you will(at last!) learn how to code a simple Love2D "game",
that displays text, images, and where you can move stuff on the screen.
I'll also explain how, and why it all works and show you some useful or interesting snippets.
First I'll show the basic structure of code for a simple not-really-game,
then I'll explain how it works, and at last, I'll give you some tasks to do.
Like usual, you can find the reference with terms explained, useful code snippets, and links at the end of this tutorial.
Intro:
First off, create a new folder for your project, it can be located anywhere,
it doesn't matter, then open it inside ZeroBrane, again, using the ... button on the project panel.
After that, you will need to create a main.lua file inside that directory,
it's the only file that is absolutely necessary for Love2D to be able to run your project,
since it's the main entry point, the file that is loaded and executed when your game is launched.
You can create it either from your system, or inside ZBS after you open the project, just create a new file and save it as main.lua.
Another file that is also loaded by Love2D by default is conf.lua,
it usually contains simple configuration values for your project, I'll show you an example later in this tutorial.
For now, inside the main.lua file, add the following code:
functionlove.load(arg)
print("Loading the game")
ifargandarg[#arg] =="-debug" thendebug=require("mobdebug")
debug.start()
endimage=love.graphics.newImage("image.png")
x=200y=100speed=200print("Game loaded!")
endfunctionlove.update(deltaTime)
--Horizontal movementiflove.keyboard.isDown("left") thenx=x-speed*deltaTimeelseiflove.keyboard.isDown("right") thenx=x+speed*deltaTimeend--Vertical movementiflove.keyboard.isDown("up") theny=y-speed*deltaTimeelseiflove.keyboard.isDown("down") theny=y+speed*deltaTimeendendfunctionlove.draw()
-- Set the background color to white and clear the screen to the new background colorlove.graphics.setBackgroundColor(255,255,255,255)
love.graphics.clear()
love.graphics.setColor(255,255,192,255)
localx=x-image:getWidth() /2localy=y-image:getHeight() /2love.graphics.draw(image, x, y)
endfunctionlove.keyreleased(key)
ifkey=="q" thenprint("User pressed the 'q' key, quitting!")
love.event.push ( "quit" )
endend
Code explanation:
If you want to run it, remember that you will need to resume it from inside ZeroBrane if you're launching it in debug mode.
What does this code do? Let's dissect it piece by piece:
functionlove.load(arg)
..end
This is a function definition. You might be familiar with functions from math, you know, the f(x) = x*3 kind.
Well, in programming, functions are a bit different than in math - in math a function
defines a transformation of input into output, in case of the example it transforms a number x into three times that number.
In programming, functions can do that, but usually they're a bit different -
they're not a transformation, they're a piece of code that you(or your framework) can execute,
and they can do just about anything.
In this piece of code, the function's name is love.load(), which means that
the function is called load, belongs to the modulelove, which contains everything that the Love2D framework has to offer,
and takes one argument, that we call arg here, as indicated inside the brackets,
and it contains the arguments sent to the program, of which the first in case of Love2D contains location of your project folder or .love file being executed
It's automatically executed by Love2D when you start your game, its purpose is to load images, sounds, and set up everything you might need.
Note: arg is just the name that we assign to the variable that the function is receiving,
you can just as well name it arguments, args, or even a, like some people do.
As a side-note, don't do that, try to keep all your variable and function names descriptive,
so it's possible to tell what they represent at a glance.
print("Loading the game")
Print is a function that takes a number of arguments, and prints them as text to the console.
It's often useful to print what your program is doing, so you can look at the output and tell what's happening
if something is going wrong.
In ZeroBrane, the output is displayed in the Output tab at the bottom of the screen.
ifargandarg[#arg] =="-debug" thendebug=require("mobdebug")
debug.start()
end
This piece of code checks the length of the argtable using the #arg expression,
and uses it to retrieve the last element. For example, if arg has three elements, #arg is equal to 3, and arg[3] is the last element inside arg
ZeroBrane sends "-debug" as the last argument when running in debug mode,
so we check for that, import the mobdebug module under the name debug,
and then start it so ZeroBrane can use it to provide us with various useful debugging features.
This piece of code defines three global variables, global means that they can be accessed from anywhere inside your game.
As you might have guessed, the first line loads an image, called image.png,
so you will need to create an image file called that, and put something inside.
Feel free to fire up Gimp, Paint.NET, Krita, or any other graphic program and draw whatever you want.
If you don't feel like doing that, have a sample image that I drew, feel free to download and save it as image.png
The other two variables, x and y will from now on hold coordinates for where we want to render our image,
and speed will determine the distance, in pixels, that our image moves when a key is held down.
functionlove.update(deltaTime)
...end
Just like love.load, this function is automatically executed by Love2D,
but while love.load is executed once when our game starts, love.update is executed every frame,
before love.draw, which takes care of rendering, and it handles updating the game logic.
It takes a single parameter, the delta time, which is the amount of time elapsed since the previous frame in seconds.
For example, at 30 frames per second, it will be equal to 1/30 or 0.0333
--Horizontal movement...--Vertical movement
Those two are comments, they exist for the programmer(s) to explain, document,
or simply visually separate blocks of code. In Lua, comments start after -- (two dashes).
You can also use multiline comments, that start with --[[ and end with ]]--,
everything between those will be treated as a comment.
Since the blocks for horizontal and vertical movement are very similar, I will only explain one.
A couple of new concepts are introduced here, first off, love.keyboard.isDown(key) is a Love2D function that returns
a boolean value, true if the key is beind held down, or false if it's not.
Second, it's used for the if-then-else expression, which takes the following form:
The condition can be anything, values of nil and false will count as false,
everything else will count as true.
In our code, the love.keyboard.isDown("left") is used as a condition,
it's evaluated while running the code into either true or false.
I used ... here to denote any arbitrary code that is executed if the condition is true, code can only start after thenkeyword
Next up, is the elseifkeyword, it contains a second(or third, fourth, etc. - you can have multiple elseif sections inside a conditional block)
condition, if the previous one fails, and code to be executed if its own condition is true.
After that, else is the final clause(like elseif, it's optional, you can very well only have if condition then ... end)
and the code inside it is executed if all previous conditions fail.
Finally, end marks the end of the block, just like with functions and all other blocks in the Lua programming language.
x=x-speed*deltaTime
Lastly, these four lines change the values of the global variables x and y.
Like explained earlier, deltaTime is used to make sure that the speed is constant regardless of the framerate -
if our game was running at 1 frame per second, deltaTime would be equal to 1, and x would move by the value of speed
every time love.update is ran, if it was 2, deltaTime would be equal to 0.5,
ensuring that x would still change at a constant rate of 200 per second.
functionlove.draw()
...end
Just like the previous two love. functions, love.draw is another Love2D function that you can define,
it takes no arguments, is executed after love.update, and usually is used for rendering whatever your game needs to the screen.
Technically, it can contain the same logic as inside love.update, but doing that is a bad practice,
and since it doesn't receive the delta time parameter, you can only use fixed amounts per frame,
which means that speed of the game will depend on framerate.
As a side-note, old DOS games used to do that, which caused issues because their framerate was not limited,
and they ran extremely fast when ran on better computers. In Love2D,
the framerate is usually limited, so that won't happen, but if your game has an uneven framerate,
due to other programs running in the background, or due to doing something that uses a lot of CPU every once in a while.
If using vertical synchronization, it also means that people's game will run faster or slower depending on what monitor and settings they have.
Before I explain the rest of the contents of this function, note those two variables.
They're prepended with the localkeyword, which means that they're local variables -
they exist only inside our love.draw function, likewise, if you declared variables as local inside another function,
they would only exist inside that function. The x and y the two expressions use, however, are the global variables -
the local ones don't exist until after their definition.
If you're interested in the math that this does, they simply make the image center at (x, y) -
love.graphics.draw draws the image left top corner at (x, y).
You might have noticed, that unlike love.keyboard. functions and love.graphics. functions,
getWidth() is written after :, this is because image is an object, : is just syntax sugar,
and it's equivalent to Image.getWidth(image), as Image is the type of our image variable.
It's a Love2D type representing images, so as you might have guessed, what : does is send our instance to the
function of that type. Don't worry if you don't understand this, it's a slightly more advanced concept.
For now all you need to know is that : is for executing functions on objects.
Finally, here you have the code that does the actual drawing, I'll explain the functions used one after another.
You can find more love.graphics functions and their usage in reference at the end of this tutorial.
love.graphics.setBackgroundColor(255,255,255,255)
This bit of code sets a global Love2D value, the current background color to white.
First three values are respectively red, green, blue components of the color.
The last value is called alpha - opacity of the color.
love.graphics.clear()
This line clears the screen, filling it with the currently set background color.
You don't actually need it, since Love2D clears the screen every frame automatically,
but I decided to include it here anyway, as a kind of example.
love.graphics.setColor(255,255,192,255)
Similarly to love.graphics.setBackgroundColor, this function sets the color that will from now on be used for drawing objects.
In case of geometric shapes, this will be their color, in case of images, they will be tinted, in this case, they will be slightly yellow.
Note that this sets the color globally, and it will persist until you set it again, so if you did:
The image2 image would also be drawn tinted!
To prevent that, make sure to set the color to white(255, 255, 255, 255) after you're done with your operations.
love.graphics.draw(image, x, y)
This line calls the love.graphics.draw function with three parameters -
the image that we want to draw, and its position.
This function can take more parameters, but for now you won't need them,
you can find them all on this wiki page for all of them.
Note that there are two function under this name on that page - they're actually the same function,
but its behavior differs based on the arguments.
For now, out of all those, only the fourth argument, rotation could be useful to you -
it's angle in radians.
Lua has two built-in functions for converting between radians and degrees - math.rad(angle) and math.deg(angle)
Also, note that all arguments to functions can be either variables or values.
Operations like addition are also valid, since they evaluate to other values(for example, 2 + 2 evaluates to 4)
Another of love functions that you can define your game's behavior,
in case of love.keyreleased, it's a function executed when the player releases a key,
with the key just released passed as an argument. If multiple keys were released,
this function will be called multiple times for each of them. Its on-press counterpart is love.keypressed, and it takes identical arguments.
The key argument is a string or a single character, you can change it to "s" for the s key, or any other character.
Special strings are used for keys like enter, space, etc.
I put a link with all the key codes in the reference at the end of this article.
Finally, the love.event.push("quit") line, tells Love2D to execute the quit event - quit the game.
If you're curious, the same can be done with other events, such as love.event.push("keypressed", "q")
Tasks, exercises, ideas:
WIP: Unfinished
3.1.
3.3. Small exercises:
Change the game to quit when the key is pressed instead of released
Look in the references for a screenshot code snippet. Integrate it into the code so that you can both quit and take a screenshot. You can use elseif, but you don't have to.
Add a key that you can press to move our object up, and release to move it back down. You will need to have both the love.keyreleased and love.keypressed functions defined for this task, feel free to copy code of one into the other and then change it. Don't copy quitting from one to the other.
Reference:
4.1. Terms:
Alpha value - in programming, alpha is simply opacity of a color, image, or anything else that is displayed as graphics. Zero alpha is completely invisible, maximum(usually 255, in some contexts 1.0) alpha is completely opaque.
Data type - In programming, a data type refers to a type of data that computers can store. Types can be simple, such as a single integer number, a string of characters(in other words, usually text), a boolean value(true or false), or null(no value, in Lua nil is a null type), or complex - contain multiple elements of simple or complex types. In most languages, including Lua, you can define your own types. Types are usually instantiated
Frame - To achieve smooth execution and display, games need to be updated and displayed on the screen multiple times a second, usually the minimal number is 30 frames per second(FPS) for slower games and 60 for fast paced ones. By default, Love2D uses vertical synchronization to control the framerate.
Function - A unit of code, that performs some operations, functions take arguments(inputs), perform operations, using(or not using) them, and then return one or more outputs. In Lua, functions are defined as function name(arguments) ...code... end
Importing - Refers to loading an external module
Instance - Look at instantation
Instantiation - A data type is just the definition of something, and does not contain actual values, and types are instantiated, which means creating a variable of a given type. For example, variable of string type can store text values, such as for example "hello".
Keyword - A symbol, usually a word, reserved by the programming language that has a special meaning and cannot be used as an identifier(name) for a function or a variable
Module - In programming, modules are self-contained units of code, they contain things such as functions, data types or other (sub)modules , that you usually can import into your own code to use it. Also known as libraries, though subtle differences exist. Love2D has the main love module and a number of submodules, such as love.filesystem for reading and writing files, love.graphics for graphics, or love.physics, that allows you to use a physics engine called Box2D. I'll show you how to do this in one of the future tutorials. Modules can depend on other modules, for some or all of their functionality. In Lua you import modules using require("module_name.submodule") function.
Namespace - A container for identifiers, functions, variables, etc.
Rendering - The process of generating and displaying an image from data, in our case, the love.draw function renders an image to the screen.
Syntax sugar - Special syntax for things that are possible without, that is shorter and easier to write and read. An example is variable += 2 in C-like languages, that Lua doesn't have. Equivalent to variable = variable + 2
Table - A data type that connects keys with values. The process of accessing those values is referred to as indexing, for example: someTable[1] returns the value associated with the numerical key 1
Variable - A name associated with a value, for example in Lua, a = 20 will assign the numerical value 20 to a variable called a
Vertical syncrhonization - Also known as vsync, it's a technique that synchronizes the framerate(amount of frames per second) with what your monitor can and is currently set to display. Nowadays, that number is very rarely under 75.
4.2. Code snippets and functions:
Data types and examples of values:
-- number - simply, numbers, both integers(1, 2, 3) and real numbers(3.5, 0.01, 100.0)n=12-- string - strings of 8-bit characters to be exact, commonly used to store text values, for example "hello there", "magic", ""welcomeMessage="Hello, stranger!"-- boolean - a value that is either true, or false. Usually used in conditions and for managing program logicisPlayerAlive=true-- nil - nothing, an absence of any other valueisPlayerAlive=nil-- this will also delete the isPlayerAlive variable-- tables - collections of values, either named or unnamed, in which case they act like lists of valuesposition= {x=10, y=20}
names= {"Alex", "Amanda", "Stephanie", "John"}
-- functionfunctionmultiplyNumber(number, multiplier)
returnnumber*multiplierend-- thread - a thread of execution, it's a slightly more advanced concept that you don't need to be concerned about. It's a separate thread of execution, that can run at the same time as the main program and other threads.-- userdata - Lua is a language designed to be used inside other programming languages, userdata is a type used for accessing types defined in such other languages
Useful functions inside the love.graphics module and their example usage:
Note that all functions except drawing images need the coordinates to be offset by 0.5 pixels,
as 0, 1, 2 are top-left coordinates of the pixels. With variables, just do x + 0.5
-- love.graphics.circle - Draws a circle.-- Definition: love.graphics.circle( mode, x, y, radius, segments )love.graphics.circle("fill", 300, 300, 32, 24)
-- Circles are drawn as polygons, the last argument, segments, is how many segments to use:-- 3 is a triangle, 4 a square, 5 a pentagon, etc.-- The first argument is either "fill" for solid circles, or "line" for only the outline.-- I'll show you later how to change line, filling, etc.-- love.graphics.draw - Draws objects(usually images) on screen.love.graphics.draw(image, 0, 0) -- Draw image at top left corner on the screenlove.graphics.draw(image, 200, 200, math.rad(45)) -- Draw image rotated by 45 degrees(they need to be converted into radians)love.graphics.draw(image, 200, 200, 0, 2.0, 0.5) -- Draws image, 2x wider(x scale), and half the height(y scale)--You can also use objects called quads to draw parts of the image only, but their usage is slightly more complex, I'll show you in a later tutorial.-- love.graphics.line - Draws line(s) between point(s).love.graphics.line(0.5, 0.5, 100.5, 100.5) -- draws a diagonal line from top left corner to coordinates (100, 100)love.graphics.line(0.5, 0.5, 100.5, 100.5, 0.5, 100.5) -- draws two lines connected to each otherlove.graphics.line(0.5, 0.5, 100.5, 100.5, ...) -- you can add as many vertices as you'd like-- love.graphics.point - Draws a point.love.graphics.point(20.5, 20.5) -- draws a single pixel at (20, 20)-- love.graphics.polygon - Draw a polygon.-- Just like love.graphics.line, this takes a list of points as their x and y coordinates,-- but it needs at least 3 points, and connects them all to make a polygon.-- Just like with love.graphics.circle, first argument is either "line" or "fill"love.graphics.polygon("fill", 100, 100, 200, 200, 100, 200) -- draws a solid trianglelove.graphics.print-drawstextonthescreenlove.graphics.printf-love.graphics.quadDrawsaquadrilateralshape. 0.9.0
love.graphics.rectangleDrawsarectangle.
love.graphics.triangleDrawsatriangle. 0.9.0
Take a screenshot when the F2 key is pressed
functionlove.keyreleased(key)
ifkey=="f2" then-- Add the current date as a number of seconds since the date called Epoch-- (when we started measuring date on computers)filename="screenshot" .."_" ..os.time()
-- Get an ImageData object containing what is currently displayed on the screen-- note that it's not an Image that you can render to screen!screenshot=love.graphics.newScreenshot( true )
-- Save it as "screenshot_123456789.png"screenshot:encode(filename..".png")
endend