Programming with PICO-8: First Steps
Category / Tutorial
Welcome! I’m going to assume that if you are reading this article, you are interested in making games and learning to program! Fantastic! This article is going to meet you at the ground floor, by covering the basics of computer programming, as well as getting you on your way towards your first game on the PICO-8!
Getting Ready
First, go to www.pico-8.com and install PICO-8, if you haven’t already. Got it? Good, now start it up! A short boot animation will play, and then you’ll be facing a screen that looks like this:
This is called the console and by typing in commands, we can tell the PICO-8 to do anything we want it to do.
What Is Programming?
Computers are, at their core, quite dumb. They need to be told exactly what to do, in order to do anything interesting. People tell computers what to do through a set of instructions, or statements, collectively referred to as a program.
For a moment, imagine you want someone to bake you a chocolate cake. You give them a recipe which outlines all the ingredients and steps necessary to do so. In theory, anyone following the recipe perfectly should be able to produce a chocolate cake. A program is like a recipe for the computer to follow.
If you’ve ever looked at a professional recipe, you’ll see that they often use certain words, in a very specific way: “Beat the eggs” or “Fold the mixture”. Cooking recipes give certain words special meanings, which are easily understood by anyone following the recipe. These words help to make up the language that the instructions are written in.
Computer programs are also written in a specific language, called a programming language. Unlike in cooking, where most recipes will use the same language, there are hundreds of different programming languages to choose from. Don’t worry though, as you’ll only need to learn one for now: Lua.
The Lua Programming Language is designed to be very easy to use, and is very popular in the video game industry. It is the language of choice for contemporary fantasy consoles such as the PICO-8 and TIC-80.
First Words
Alright, now that we’ve covered what programming is, why don’t we do some? Go back to the PICO-8 console and type in this statement:
print(‘Hello world’)
Press the Enter key. You should see on the line below “Hello world”. Congratulations, you’ve executed a very simple program, which writes the text to the screen. It might not look like much, but there’s quite a bit going on.
- “print” is a function that we wish to execute. We call the function by placing a pair of brackets next to the name of the function.
- As in mathematics, functions have inputs, called parameters, which can affect the outputs. We put the parameters inside the brackets of the function call.
- In this statement, the parameter is the string of text, “hello world”, which we want to be written out.
We could write a whole game using the console, but it wouldn’t be very convenient since we would have to execute each line. Fortunately, we can press the ESC key to enter the code editor. In this tool we can write whole programs before executing them. Open the code editor and write our one-line program from earlier. Then, press ESC again to return to the console. Now type RUN and press Enter to see the program execute. Awesome!
Assignments And Arithmetic
Printing text isn’t hugely exciting, so why don’t we try some arithmetic. Computers are really good at handling mathematical operations such as addition, subtraction, multiplication and division.
Open up the code editor and replace what’s in there with the following:
x = 2 + 2
print(x)
If you are used to doing maths at school, the first line might look a little odd. Usually, the sum comes first, and the equals sign after, but here it is backwards. The statement “x = 2 + 2” tells the computer “add 2 and 2 together, and remember the result as ‘x’”. This is called “assigning to a variable”. After this, we can tell the computer to output whatever is stored in the variable “x”.
Variables are ways of storing data that we have, but are going to need later on. We might not know what the result of a statement is until the program is running. Despite this, assigning it to a variable lets us use it in our code. We can then use mathematical operators to do addition (+), subtraction(-), multiplication (*) and division (/).
Enter this into the code editor, and see if you can figure out what will be printed:
x = 2 - 1
x = x * 2
x = x + x
x = x / 2
print(x)
Did you get 2? If so, well done!
It’s important to note that we can store all types of data in a variable. Lua is a dynamically-typed programming language, so we don’t have to tell it what type of data we want each variable to be; it just guesses while the program is running. We’ve already seen two data types: strings and numbers. The last important type we will encounter today is the boolean. Boolean variables have one of two values: true, or false. You could use these to record yes/no answers to things like “is the player on the ground?” or “is my character’s weapon charged?”.
On One Condition...
Programs would be pretty boring if we could only execute one line after another. What if we want to do something only in certain circumstances? Fortunately, programming languages provide conditional statements which let you specific circumstances under which a block of code is to be executed. We can do this in Lua using an if statement, which looks like this:
x = 4
print(“is it five?”)
if x == 5 then
print(“It’s five”)
end
print(“now we know!”);
The lf-statement is the third line. It follows the format of “if [condition] then”. If the condition has the value “true”, then the code that follows is executed. Each if statement needs an “end” to show where to stop. See what happens if you change the value of x from 4 to 5.
Sometimes, we want to run one block of code when the condition is true, and another block when the condition is false. We could do that by writing something like this:
x = 4
print(“is it five?”)
if x == 5 then
print(“It’s five”)
end
if x ~= 5 then
print(“It’s not five”)
end
However, this is a little verbose, since we need to use the condition and its negation together which could get confusing. Fortunately, lua (and more languages) provides a feature called an if-else statement. The above code could be written like this instead:
x = 4
print(“is it five?”)
if x == 5 then
print(“It’s five”)
else
print(“It’s not five”)
end
You can also nest if statements inside each other, to check for more complex sets of conditions, and deal with multiple outcomes.
x = 4
print(“is it five?”)
if x == 5 then
print(“It’s five”)
else
if x > 5 then
print (“It’s too big!”)
else
print(“It’s too small.”)
end
end
This could get pretty unruly if we need more than 3-4 outcomes, so lua lets us do this:
x = 4
print(“is it five?”)
if x == 5 then
print(“It’s five”)
elseif x > 5 then
print (“It’s too big!”)
else
print(“It’s too small.”)
end
Now we don’t need a huge number of “end”’s at the bottom.
Boolean Operators
If statements require expressions which result in either a true or false value. We can use boolean operators to do comparisons between numbers.
print(4 == 4) -- Should be true
print(4 == 5) -- Should be false
print(5 ~= 5) -- false
print(5 ~= 4) -- true
Above you can see an example of the equality operator (==) and the inequality operator (~=). Because we are using the PICO-8, we can use (!=) as an inequality operator as well. This is not part of standard Lua. These operators check to see if two values are the equal , or not, and return a boolean value of true if they are. This works for strings, numbers and boolean values. We can also check to see if a number is less than or greater than another.
print(4 < 5) -- true
print(5 > 4) -- true
print(5 <= 5) -- less than or equal to
We can combine these boolean expressions together using the “and” operator and the “or” operator. These should behave roughly as you’d expect, except that the “or” operator returns true if either parameter is true, or if both are true.
print (4 == 4 and 4 < 5) -- true
print (4 < 5 and 5 < 4) -- false
print(false or true) -- true
print (false or false) -- false
print(true or true) -- true
Finally, we have the “not” operator, which flips the boolean value of the input, so a true value becomes false and vice versa.
print(not true) -- false
print(not false) -- true
Going For A Loop
The other thing computers are good at is repeating actions. So far, if we wanted to repeat ourselves, we’d have to write the code out over and over, like this:
print(“hello”)
print(“hello”)
print(“hello”)
print(“hello”)
print(“hello”)
This is tedious. Instead, we can use a for-loop, which repeats the code in its block a certain number of times:
for i=1,5 do
print(“hello”)
end
The loop-counter i is actually a variable, so we can access it while we are inside the loop block, to include it in our code. Sometimes it might be important to know how far through a loop we are.
But sometimes, we don’t know how many times we want to loop. For those situations, we can use a while-loop, which will loop until some condition is false:
i = 0
while i < 5 do
print(“hello”)
i = i + 1
end
While loops don’t come with a loop counter, so we have to create our own first. It’s important to know that if the condition isn’t met when you first encounter the loop, it won’t execute at all.
i = 0
while i > 0 do
print(“not happening”)
end
print(“happening”)
If you need a loop to execute at least once, you can use the repeat-until loop, which looks like this:
i = 0
repeat
print(“hello”)
I = i + 1
until i > 5
For all the examples in this section, I encourage you to play around with the starting value of i, as well as adjusting the conditions, to see how they behave.
Important Note: If you make a while or repeat-until loop which can never satisfy its condition, it will loop forever, so no code afterwards will ever execute.
while true do
print(“forever”)
end
Putting It All Together
Now that we’ve covered all the basics, we are going to start making a simple game, which we will expand upon in other articles in this series.
Take a look at this code, and see if you can figure out whats going on. Don't worry if you don't recognise a couple of the names of functions, those are explained down below.
x = 64
y = 64
while true do
-- update
-- move the baton
if btn(0) then
x = x - 2
elseif btn(1) then
x = x + 2
elseif btn(2) then
y = y - 2
elseif btn(3) then
y = y + 2
end
-- draw
cls()
rectfill(x-3,y-3,x+3, y+3, 8)
flip()
end
There’s a few things going on with the above code, so we will walk through them together.
At the top we create a pair of variables, x and y, for storing the player’s coordinates on the screen. Then, we start an infinite loop, which will be our game loop. Almost all video games are built on a constant loop of processing player inputs and game events, before drawing everything to the screen. Then, it repeats.
During the update phase, we process the inputs, using a function provided by the PICO-8 called btn(), which returns true if the numbered button is currently pressed. You can find out more about functions the PICO-8 gives you access to by reading the manual. We check each directional button in turn. If any are pressed, we adjust the x and y directions accordingly.
Now we enter the draw phase. We run cls(), which clears the screen of anything that’s been previously drawn. Then we use rectfill() to draw a rectangle to the framebuffer at the x and y coordinates, to represent the player. Finally, flip() is called, to take what’s on the framebuffer and display it on screen.
The result should be that you can move the red box around the space with the arrow keys, which is where most games begin!
Conclusion
In this article we’ve covered the essential pieces of imperative programming languages and how to use them. These ideas can actually be applied to lots of languages, so even though we’ve just used Lua for all our examples, if you can master these concepts, you’ll be well on your way to learning others.
The next article in this series will cover two more important language features: Functions, which allow us to break down our code into more manageable and reusable chunks, as well as Tables, Lua’s infinitely versatile data type, which lets us maintain more complex data about the state in our games.
Useful Links
Game programming Patterns - Game Loops
PICO-8 Manual
Programming In Lua