Now that we have covered each menu of Pico-8, we’re ready to begin game development! There are different ways to start a project, such as coding, drawing sprites and writing music. For this tutorial, I’ll be focusing on the coding aspects since that is my area of expertise.
The Game Loop
The Game Loop is the core of any video game. It is the heart and engine of a game project. Basically, a video game is a software program that runs in an endless loop, checking for player input and responding appropriately. Pico-8 has three main functions for the game loop: _load(), _update() and _draw(). Technically, you can skip these functions and write the game loop yourself, but for most instances, it’s easier and simpler to use Pico-8’s built in game loop callback functions. These functions are case-sensitive, so if you try to use capital letters, they won’t work correctly.
The only optional callback function of the built-in game loop, _load() is a one-time function that Pico-8 runs when you start the game. You can use this function for loading your game resources, such as your starting player, maps, configurations, game states, and anything else you want loaded in just once at the start.
The _update() callback function is run once each frame of your game (typically 30 times a second). Use this function to update anything your game requires, such as moving the player or enemies around, collision detection, health, game states, keyboard inputs, etc. Do not put any functions for drawing in here; they won’t work and will waste resources. Instead, place all your draw calls inside the next game loop function, _draw().
The _draw() callback function is also called once each frame. It’s a double buffer strategy that lets you draw sprites as well as simple geometry such as lines, squares, circles, etc. I highly recommend that you place cls() at the top of your _draw() function, since this will clear your screen at the start of each frame. Otherwise, your draw images will stay on the screen, causing them to smear if they move or change and making an incomprehensible mess.
Now that we’ve gone over the essential functions, we’ll begin to write these functions into our game code. Write the code like this:
Lua uses end statements to differentiate code blocks. It is also customary to add a tab to the inside of a block so that the programmer can more easily separate each part on sight.
Basics programming concepts
Let’s conceptualize the basic building blocks of programming languages. Values are exactly what they sound like – they’re something that has some pre-defined value that cannot change. Examples of this include the number 5, the boolean false, and the text “Hello world!”. Each value has what’s known as a datatype, which determines what kind of value it is. Lua has a total of 8 datatypes, but this tutorial will only look at 6 of them since the other two aren’t necessary for game development.
Here are the 6 basic datatypes that we’ll be examining:
- Number – This represents any real or double precision floating point number, such as 5, -3, 8.7, etc.
- String – In programming, text is called strings. You can also think of them as arrays (or lists) of characters, where a character is one letter, number, symbol, etc. Examples of strings are “Hi there!”, “#games”, and “5.6.” To differentiate between text and numbers or variables, surround the string with double quotation marks. Otherwise, Lua will think you’re referring to a variable or number. “5” is the string 5 while 5 is the numeric value 5.
- Boolean – A boolean is a logical value that can only have two values: true or false (make sure it’s lower case). When you are evaluating conditions, such as checking whether the player has any health or not, the result of the condition will be a boolean value.
- Nil – nil is a special value that means none or nothing. When you first create a variable, nil is the default value.
- Table – A table is basically a container for other values. Lua tables are fairly complex since they are the only container datatype in the language. You can use them to store large amounts of similar data or complex objects, such as enemies. We’ll take a look at tables later on.
- Function – A function is a piece of code that you can call, meaning that you can type the function name in and run whatever it does wherever you want. Functions are used for pieces of code that you want to reuse, such as collision detection. _load(), _update() and _draw() are all examples of built-in functions. You can differentiate a function by the fact that a pair of parentheses are at the end of the function name. In addition, when you define them, they start with the keyword function. Sometimes other values or variables, called parameters, are inside these parentheses. Functions will be covered in more detail in a later part of the tutorial.
Variables are named values that can have their values changed. If you’ve taken algebra, they have the same function. For example, you can have a variable named x with a given value 7. You can assign variables the values of other variables, meaning that the variable’s value changes when the other variable’s value updates. So if x = y and y = 5, then x = 5. If y changes to 8 later on, x will change to 8 automatically.
You can name variables anything you want within certain limitations. The name of a variable can be composed of letters, digits, and the underscore character _. It must begin with either a letter or an underscore. Take note that while Lua itself treats upper and lower case separately, Pico-8 itself does not distinguish between the two, so be sure to use lower case everywhere. As examples, player_health and _enemy_3 are valid variable names, but 5_tree is not. Variables are the meat and potatoes of programming, and you will use them to keep track of everything in your game, from the player to the game state.
Suggestions for Variables
I would not suggest starting a variable name with an underscore character since built-in variable names such as _load use this style, and you shouldn’t confuse your created variable names with the built-in ones. In addition, you should name your variables with logic and consistency, to make things easier on yourself and others (if you’re working on a team).
Names such as a or b don’t describe what they are, whereas player_health tells you exactly what it is. In some special circumstances, such as using a temporary variable, you may in fact want to shorten the variable name, but in general you should avoid this. You should also maintain consistency with your names. It’s up to you if you want to use underscores in your variables such as player_health, or if you want to forgo those, such as playerhealth. Keep in mind your variable names cannot have spaces in them.
So now that we know what variables and values are, let’s discuss how we give them values. In programming, when you give a variable a value, you call it assignment (i.e. you are assigning a value to the variable). To assign a value to a variable, simply use an equals sign. So to give 6 to the variable room_number, you type room_number = 6. That’s all there is to it.
A large portion of your game will be multiple lines of assignment statements. Unlike some languages, you do not need to place a semicolon at the end of each statement; the Lua interpreter will figure out each statement on its own (or complain that the statement is illegal). To separate each statement, you use whitespace. You can accomplish this by writing each statement on a new line, which helps to visually organize your code.
Whitespace is used by programmers to lay out their code nicely and make it easier to read and understand. The Lua interpreter ignores whitespace, so you are free to use it wherever you see fit. Examples of whitespace include spaces, tabs, and new lines. Try to be consistent with your whitespace usage, and avoid using too much or too little.
Lastly, comments are text written by the programmer for themself and others to explain what pieces of code mean. It’s a good idea to write comments regularly since chances are, you’ll forget what parts of your code does. In Lua, single line comments start with — , while multiline comments are written with –[[ in the beginning, and ]] at the end. In Pico-8, comments are grayed-out.
That’s it for today’s tutorial. Next time, we’ll dive further into Lua and begin working on a basic game.