PICO-8
Main Menu Cartridge

This lesson continues where Main Menu Version 1 leaves off.
Version 1 introduces and explains what game states are and what a state machine is. So if you have questions about that, go back and watch that video:
Main Menu - Version 1This version is more efficient than the first, so we actually recommend using this in your game, after understanding why it is better and how to use it.
After you made this main menu, change it up! Try some of the challenges below to spark some ideas!
Challenges!
After following the lesson, take on some of these challenges to test your knowledge and skills!
1. If you followed Version 1 already, copy that game, and convert it to use this version.
Improved Main Menu!
Explanation of Code!
In Main Menu - Version 1, we introduced the simplest build of a state machine, and how to control the game states. This required only basic knowledge of programming so it is a good starting point for beginners. It is easy to read and understand, but not as easy for the code to run.
Efficiency is what every programmer works towards. Efficiency is a quality of wasting the least amount of resources. In general, resources are whatever is used in any type of process.
For example, if you are making a poster for a class project. Then you need to find or buy resources such as: poster board, glue, paper, scissors, etc. And you could buy 3 of everything, make 3 different posters, and choose the best one. But that will waste a lot of time and materials spent making the other 2. So that is not efficient.
It would be much more efficient to plan out your poster and know exactly which materials you need and how much. Then you should only get what you need, and use it all in meaningful ways so you have no wasted materials or time.
A good programmer will consider the use of the computer's resources and when we talk about a computer's resources, we usually mean Memory. There are basically 2 types of memory, stored memory and active memory.
Stored Memory is the total amount of data that can be saved. Every file and folder you have on your computer takes up space. And every computer has a limit of how much space it has for saving data. PICO-8 limits our games to a very small space compared to modern video games, so we are forced to keep our games nice and simple.
Active Memory is the amount of data that can be running. Every program you have open right now is using your computer's active memory. Some programs use a lot and you might notice your computer slow down and take time to load. While some programs use very little active memory. They are either small programs, or very efficient programs, and you will notice your computer loads and runs them easily.
Now then, what does all that have to do with making games in PICO-8?
Well there are so many ways to write code that does the same thing in the end. But the trick to being the best programmer is figuring out what is the most efficient way.
Sometimes, we sacrifice the most efficient way for better readability and understanding. For example:
s=1 h=10 a=5 d=3
Those are very efficient variable names because they are only 1 letter each. But what does it mean?! The person who wrote it might be able to understand it, but someone else will have to waste a lot of their time trying to figure it out.
sprite=1 health=10 attack=5 defence=3
Now these variables are a tiny bit less efficient, but way more understandable! So most of the time, we should balance these two to find the best way, which isn't always the most efficient way.
Version 1 is a good example of writing game states for understanding but not for efficiency. And here's what is really not efficient about it.
--main update and draw function _update() if scene=="title" then update_title() elseif scene=="menu" then update_menu() elseif scene=="game" then update_game() elseif scene=="gameover" then update_gameover() end end function _draw() if scene=="title" then draw_title() elseif scene=="menu" then draw_menu() elseif scene=="game" then draw_game() elseif scene=="gameover" then draw_gameover() end end
We don't quite get this far in the lesson, but if you continued to build your game this way, you would add each game state in another
elseif
statement. And this could get very long. So not only does it waste a lot of code which takes up storage memory, but it also takes a lot of active memory to constantly run each of these checks every tick of the game. So that gets expensive and uses too many resources.
Luckily there are more efficient ways of doing the same thing and skipping those checks completely!
PICO-8 needs _update
and _draw
functions to run.
So we wrote:
function _update()
end
function _draw()
end
Then we used a variable to store the active game state name and check that variable to run the correct game state. Even though that is easy to follow, it is not efficient, but what it is doing looks something like this:
So basically we are just setting _update
to use our active game state's update function.
And the same for draw.

But here is something you might not have known: Function names are actually just variables that hold functions instead of just a word or a number.
What does this mean??
Well it means that we can treat function names just like variables, because that's what they are! (this is unique to the Lua programming language)
So we can create an empty function:
function myfunction()
end
And now myfunction
is a variable, and we can set that variable to whatever we want, for example, a copy of another function's code.
function myfunction()
end
function _init()
myfunction=print --copies print() code into myfunction()
myfunction("hello world")
end
--prints hello world
You should already know the built in function print()
and usually the first thing we all learn to do in any language is write "hello world" onto the screen.
print("hello world")
is how we normally do that in PICO-8, but because we copied the
function from the variable print
into our own variable myfunction
,
that means we can then write myfunction("hello world")
to do exactly what print()
would normally do!

Understanding that is very important to understanding how this more efficient State Machine works.
So now that we know how to copy functions from one function name (variable) to another function name (variable),
we can skip the if elseif
checks from Version 1 like this:
We could start by writing the required update and draw functions.
function _update()
end
function _draw()
end
But doing that, is really just creating two variables named _update
and _draw
.
And we would normally just create variables by writing variable_name=
right?
So by just writing _update=
, we can creating a variable named _update
, which is even more efficient than above.
Then we can jump right into setting the update and draw variables to hold the game state function code we want to run.
_update=update_menu
_draw=draw_menu
Notice how we don't use any parentheses () because we are treating them as the variables they are, and not trying to run them as functions.
In fact, when PICO-8 starts the game, it looks for variables named _update
and _draw
and tries to run them as functions automatically.
It is really important to understand all of that, to be able to understand what we will do next. So if that all makes sense, let's start building the more efficient state machine!

function _init()
--variables
x=63
y=63
--first game state
init_menu()
end
What is a variable?
By setting up your variables inside of the _init()
function,
you can easily reset your game by calling _init()
, and
the variables here have access to any custom functions you write.
That might come in handy later so it's a good practice.
So far that is the same as Version 1, but the next part is new. We call a function that will be named init_menu
meaning "initialize menu",
but you can name it whatever you want. start_menu
or open_menu
are also good names.
This function will be used to start the menu game state by setting _update
and _draw
to the code written in update_menu
and draw_menu
functions.
function init_menu()
_update = update_menu
_draw = draw_menu
end
By doing it this way, we are able to skip the entire "main update and draw" tab from Version 1 that
held the long if
and elseif
checks. To fully understand how this code works, read sections zero and one above.
So now when we start this game, PICO-8 will first run the _init()
function which will set the variables and then run the
init_menu()
function. That function will copy whatever code is saved in update_menu
and draw_menu
into the new variables _update
and _draw
.
When PICO-8 finished _init()
, it will then look for variables named _update
and _draw
, and run them as functions.
And so they will run whatever code we write in update_menu()
and draw_menu()
functions.
So that's next.
But let's also create an init_game()
function to change the main _update
and _draw
functions to run the game.
function init_game()
_update = update_game
_draw = draw_game
end
And these init_something
functions become our State Machine!
So for each Game State you want to create, just write another one of these functions that change the main _update
and _draw
variables to hold your specific update_state
and draw_state
code.

Here are the specific update and draw functions for each game state that we want to have. These are the exact same as Version 1.
The only difference is how we change the active Game State. Instead of using the "scene" variable,
now we just need to run the init_state
function for the state you want to switch to.
So in update_menu
, when the user presses button X, then we run init_game
.
function update_menu()
if btnp(❎) then
init_game()
end
end
function draw_menu()
cls()
print("press ❎ to start",30,63)
end
And in the update_game
function, when something happens and we want to run a new Game State, then we run that init_state
function.
Just like Version 1, we are only giving an example of a Main Menu state and a Game state, so in the game state, we are also simply
checking if the user presses the X button again, which will return to the Main Menu by running the init_menu()
function.
function update_game()
if btn(⬅️) then x-=1 end
if btn(➡️) then x+=1 end
if btn(⬆️) then y-=1 end
if btn(⬇️) then y+=1 end
if btnp(❎) then
init_menu()
end
end
function draw_game()
cls()
spr(1,x,y)
end
You can organize your code in PICO-8 using the tabs however you would like. In the Full Code section below, we organized all of the init
functions in the first tab,
then all of the update
functions in the second tab, and finally all of the draw
functions in the third tab.

NOTE: This is not the exact code created at the end of the video tutorials. This is more of a template that you can use to start building your game using this style of game states. We thought that would be more useful.
--inits
function _init()
--global variables
x=63
y=63
--first state
init_menu()
end
function init_menu()
--menu variables
--set state
_update=update_menu
_draw=draw_menu
end
function init_game()
--game variables
--set state
_update=update_game
_draw=draw_game
end
-->8
--updates
function update_menu()
if btnp(❎) then
init_game()
end
end
function update_game()
if btn(⬅️) then x-=1 end
if btn(➡️) then x+=1 end
if btn(⬆️) then y-=1 end
if btn(⬇️) then y+=1 end
if btnp(❎) then
init_menu()
end
end
-->8
--draws
function draw_menu()
cls()
print("press ❎ to start",30,63)
end
function draw_game()
cls()
circfill(x,y,5,11)
end
-->8
is a new tab in Pico-8. They don't appear inside the Pico-8 code editor.


font
