debug
printh
printh()
Print to the console.
PICO-8 doesn't normally start up with a console screen so you'll want to prepare your PICO-8 shortcut to open with one before you can see anything you try to printh
to it.
This tutorial, by pancelor, walks you through setting up the console for using this command to print debugging information while your game is running.
1642
20 Dec 2024
backup
backup
This command will save a backup .p8 file of the currently loaded game in your backups folder. It will save under the current filename, or as "untitled_#.p8" if you haven't yet saved and given the data a filename.
After using this command, you will be notified in PICO-8 that it has been saved and under what name:

To open the backups folder, either navigate to {appdata}/pico-8/backup or use the folder command and specify "backup":

The above command will not notify you in PICO-8, but it will open the backups folder in your file explorer and should look like this (in Windows):
927
20 Dec 2024
PICO-8 uses the standard SDL2 scheme to handle game controllers. When you start PICO-8, it will automatically detect common controllers. So make sure you plug in your controller before running PICO-8. It will also check for any custom controller settings saved in a file called sdl_controllers.txt, which should be in the same folder as config.txt. In sdl_controllers.txt, each controller setting is written on a separate line.
To create a custom setting for your controller, you can use a program called controllermap that comes with SDL2, or visit this website: Gamepad Tool.
To find your controller’s ID (as recognized by SDL2), open log.txt after running PICO-8, and search for "joysticks" or "Mapping." Keep in mind that this ID might be different depending on the operating system you're using. From this BBS Post, it is recommended to use the mapping from log.txt, paste it into sdl_controllers.txt and then modify it to your liking.
If you want to configure which keyboard keys will act like joystick buttons, you can do that using the *KEYCONFIG* tool."
1410
20 Dec 2024
Game development is the ultimate creative endeavor, with the potential to bring all forms of art, music, science and mathematics together. So it's no wonder why game developers often struggle with lack of motivation and creativity.
We have gathered experiences and advice from game developers in the community to create this reference to help you "debug" your motivation "errors" and get you productive again.
# | Error Message | Read How to Debug |
1 | I feel overwhelmed. The project is too large, difficult, or complex, and I don't know how I'll manage to finish. | Too Large of Scope |
2 | I feel lost and uncertain of what to do next or where to take it. | Lack of Clear Goals |
3 | I feel deflated like someone took the wind out of my sails or snuffed out my fire. | Negative Feedback |
4 | I feel pressured to reach the expectations I or others have for my quality of code/sprites/audio/gameplay. | Fear of Failure |
5 | I feel a desire to make something but I'm stuck not knowing what or I already started but I feel bored with my own project and progress feels like walking through mud. | Lack of Inspiration |
6 | I feel detached, separate, and alone, wondering if anyone will even care about what I am making. | Isolation |
7 | I feel like people don't understand what I'm trying to do. I question whether I should be doing something "more productive" with my time. I hesitate to show or ask others about my project for fear of them being more discouraging. | Unsupported |
8 | I feel slow and unproductive, debugging or rereading the same line of code, fighting myself to focus. | Rest |
9 | I doubt my own knowledge, abilities, and skills. I feel like a failure and a fraud. I feel like my past successes were purely through luck, and I fear that the people who think I am good will find out that I'm not. I worry that I'll never actually be as good as others think I am. | Imposter Syndrome |
10 | I feel like I've lost my drive, passion, or purpose. Like the fire in my belly has been put out and I just want to reignite it. | Intrinsic Motivation |
Too Large of Scope
Scope refers to the boundaries and limitations of a game development project, including its goals, timeline, and resources. It outlines what the project will and will not include, and helps ensure that the project stays on track and meets its objectives.
When a project or a problem within a project seems too large and complex, it can be demotivating. Break it down into smaller tasks and consider their priority and order. Create a checklist or a to-do list to keep track of progress and provide a sense of accomplishment as these smaller tasks are completed.
Instead of looking at a giant wall in front of you that you can't imagine climbing, creating smaller more achievable tasks is like turning that flat wall face into stairs. Start climbing those stairs one at a time and you'll soon be able to look back down and be proud of how far you've come.
You can also break one large project down into smaller projects. If you have a dream game in mind, break it down into it's component parts. Set the dream game aside, and take each of its component parts as a challenge to create a small game focusing on one component at a time. Eventually, you will have learned the skills to put all of those component parts together to pick back up and create your dream game.
Lack of Clear Goals
Without clear goals, it can be difficult to stay motivated. Set specific and achievable goals for each task or project, and create a timeline for completion. Having a clear sense of direction can help maintain focus and motivation throughout a long project. So take the time to step away and lay out your design ideas in an organized list of priorities of what you need to get done. Making a checklist out of them often helps.
It's also a good idea to find your MVP (minimum viable product) within your list of tasks. Ask yourself, "at what point would the game be fun to play?" All the rest is just extra icing on the cake. So lay out your tasks with the goal of reaching MVP before doing any of the extra polish.
However, sometimes we start a project without any specific idea in mind. It is very possible to develop games, starting from a single mechanic and see where it leads, hoping it becomes fun and interesting along the way. But there is a common pitfall with this approach. You can develop it in a wrong direction for too long and find a dead end or not like where it is going.
In this case, take a look at your project so far and be honest about what you feel is working and what is not working. It may be hard to admit, but you may need to cut out something you've spent too long on that is simply derailing your project. When we are developing a game by experimentation then we are bound to make a wrong decision or two.
So when working on a project that intentionally has no end goal, you must also be willing to backtrack and admit when an experiment has failed. You will stay much more motivated if you can make small course adjustments sooner than major ones later. This is because the more time and effort you put into a specific course, makes you feel more invested in that and less willing to give it up.
One way to ensure you are making smaller adjustments is to prototype ideas fast, and have playtesters try them out. Even if you love an idea, be willing to throw it away if your playtesters hate it. Then quickly try something else. Eventually the trial and error approach will reward you with a clearer image of what your game is turning out to be.
Negative Feedback or Harsh Criticism
Negative feedback or criticism can be demoralizing, especially if it feels unwarranted, or unfair, or coming from someone you expected positivity from. As much as you may want to withdraw and stop communicating with that person or within that community, fight against this feeling and continue the conversation instead.
It is possible that this person meant to be helpful not harmful. In which case, expressing your own feelings of hurt could elicit an apology and clarification from them.
It is also possible that they are offering suggestions for improvement more bluntly than you are used to. Asking them to explain more about what they mean could help you both discover the true source of their criticism and you might find that it is actually simple to improve on.
It is unlikely but still possible that this person is actually trying to be hurtful and demoralizing. In this case, it is important to recognize who these people are and realize that their opinions are not genuine and don't represent the opinions of others.
In all cases, remember that criticism is an opportunity for growth and improvement. Take a constructive approach, listen to feedback, and use it to make the project better, or embrace it to fuel and inspire you to prove them wrong.
Perfectionism & Fear of Failure
Striving for perfection can be paralyzing and lead to procrastination. Accept that not everything will be perfect, and focus on making progress instead of achieving perfection with every step. Embrace imperfection and any failures as part of the learning process and a necessary step towards improvement.
Focus on measuring yourself by your progress and small wins, and seek support from friends and community members when needed. The goal is not to get it right the first or even second time. The goal is to compare where you started with where you end up and be proud of the difference. The mistakes you make along the way are necessary to increase the amount of improvement in yourself that you will be proud of.
If you are seeking perfection, it will shine in the final product, not in your drafts, but polishing that gem is a process of trial and error.
Lack of Inspiration or Interest
If you are having difficulty starting a new project, and are feeling uninspired, then seek out inspiration through other mediums, such as music, art, or literature. Don't stare at a blank page or screen and try to force inspiration. Engage in activities that bring new experiences. Allow inspiration to come naturally and from unexpected places. You'll never find inspiration from things you already do often. So take a different road on your way home. Watch a movie you would never choose for yourself. Allow for more variety of what you take in and you'll discover more variety of output in the form of inspiration and ideas.
If you are already midway through a project and find It hard to stay interested in it, then take the time to find ways to incorporate your personal interests into the project. If you find that your interests have shifted to something else, first try to bridge your current project over to follow your new interests. Try not to set your current project aside for something that appears more interesting right now, because that will likely happen again and again and you will feel much worse when you look back on a mountain of unfinished projects. Instead, use that interest in the new, to fuel your perseverance of completing the old.
If you don't see how to align your new interests with your current project, then make a decision to only allow yourself to start the more interesting project after you have completed the current one. Use your interest and inspiration in your next project as your reward and let that fuel your motivation towards completing the current one. You will be much happier for it in the long run.
Isolation & Loneliness
As hobby game developers, we are usually working solo in secluded spaces for long times, hyper focused on our projects, and happily introverted. But introverted or not, working alone for long periods can be isolating and demotivating. So don't forget to check in with yourself if you start to feel too detached from others.
Reach out to your friends and try to engage in something more social. It may be trying to have a board game session, going to see a movie, or doing some physical activity you enjoy together.
Within game development, seek out opportunities to collaborate with others, whether through involving your friends or asking within your online communities. Engage with other developers and seek feedback and support.
If any of those options don't sound appealing, even a simple change of environment could help. Instead of doing your work at home alone, bring your work to the library or café. Simply being among others could be all the social rejuvenation you need to feel comfortable and motivated again.
Unsupported
Within a hobby community, a negative or unsupportive environment can be demotivating, especially for new members. Seek out a more supportive group within the hobby that values encouragement and positivity. If you feel it is possible, advocate for changes in the current environment away from the unhelpful, antagonistic, or demeaning responses you've received in the past. You may be surprised how your courage to address the issue can inspire others to speak up and agree with you.
Another way we can feel unsupported is from our close family and friends who don't share the same passion or understanding of this game development hobby or potential career. Be honest with them about your passion and don't shy away when they try to make snide comments or remarks that make you feel ashamed of how you spend your time. Communicate with them openly and come to an agreement so that you don't feel discouraged by their lack of support.
At the same time and just as important, listen to what they have to say, and reflect on it. We can indeed get carried away by our passion projects and neglect people or responsibilities that should have more priority in our lives. The important thing is to communicate and adjust your life so that you don't feel guilty of the time you do spend in the hobby and the people around you will be more encouraging of time spent here as well.
Working Too Long
Often times, our motivation to work on our project can even be too strong! It can keep us working for too many hours without breaks and can lead to burnout. Take the time to check in with yourself and be honest about your current ability to focus. Prioritizing rest is an important way to help maintain motivation levels. We often overlook eating or sleeping when we are enjoying what we are doing. The tough part is to stop yourself when you obviously need a break, especially when you feel like you are close to solving a bug.
Well if you are fighting to use what little attention and energy you have left to solve something you feel should be simple and obvious, chances are that it is simple and obvious, and you just need sleep in order to see it clearly.
Ask any programmer because we have all experienced regretting so many wasted hours staring blankly at a problem, only to give up feeling defeated, going to bed, and then immediately realizing the solution when we wake up. We all wish we just took the necessary break sooner and paid better attention to our body's need for food and/or rest.
Imposter Syndrome
This is a common feeling among game developers. Game development is a field that stretches into many disciplines of learning, and each corner of the hobby can be learned to a great depth. It involves math, language, logic, art, music, writing, story telling, design, and more. Each of us have different strengths and skills and it's near impossible to be great in all of those aspects.
So it makes it easy to see other game developers who are great in one or two areas and think they are simply far better overall and that can make you feel inadequate by comparison. But the truth is, those developers experience the same thoughts and feelings about themselves.
Take time to reflect on your achievements and give yourself credit for your successes. Keep a record of your accomplishments, and remind yourself of them when you start to doubt your abilities.
Share your feelings with others in the community, especially the ones you look up to, who can offer support and perspective. You may be surprised to learn that many of them also experience imposter syndrome.
Challenge negative thoughts about yourself by asking yourself if they are truly based on evidence or if they are assumptions. We often fall into the bad habit of assuming others are simply being nice when they give compliments and don't actually mean it. Throw those assumptions away and accept the compliments you've received.
Recognize that making mistakes and experiencing failure are natural parts of the learning process and that everyone, whether thought of as a master or expert, always has room to learn more. Know that you will earn more respect by admitting and displaying your own shortcomings than by appearing as flawless. You don't need to be perfect to maintain and gain respect from others.
Lost Intrinsic Motivation
Many of us don't actually know why we were drawn to this hobby, or what compels us to put so many hours into learning and creating. Our intrinsic motivation (the motivation that comes from within) is a very unique thing to each of us. It could be a desire to be recognized, to help others, to have fun, to learn something new, to prove something, to express something, to achieve something, or a number of others.
The important thing is to look within for motivation, not at what you might gain externally. Stop chasing likes and follows on social media. Ask yourself, "what fueled you before? What emotion drove you?" Did you achieve that in your last project, and now you don't have that to drive you anymore?
Find what is at the center of your personal motivators and reconnect those reasons to your current project. Make the decision to hold to this goal.
If you cannot discover and reignite your internal flame this way, then try communicating it with close friends who are good at listening. Trying to get others to understand what motivates you could help you to better understand yourself, and you might just have a realization along the way that sparks the flame you were looking for.
4403
31 Dec 2024
Are you having trouble understanding the error message in PICO-8? Or do you want to know how to start to debug such an error? This debugging resource was made for just those purposes!
How to Read Error Messages
First of all, let's understand how to read the PICO-8 Error Messages and breakdown its parts. This is an example of a PICO-8 error message:
syntax error line 9 (tab 0)
erroring here
syntax error near 'here'
in _update line 17 (tab 0)
The first line of the errors usually start with either:
SYNTAX ERROR | A problem with breaking code structure or rules. |
RUNTIME ERROR | A problem found while trying to run your game. |
Then it will tell you where in your code it found this problem, not necessarily where the real problem is, just where it was noticed.
LINE _ (TAB _ ) = The line number and code tab number in the PICO-8 editor
On the next line of the error message, it will print the exact line of code where the error occurred (again, that's not always where the problem actually is). In the above example, the words "erroring here
" are taken from the code where the error was triggered.
The next line of the error message is the specific type of error that happened and what word or symbol on that line of code it is near. Sometimes this points directly to the problem, often times it just gets you closer to the real problem. You can look up your error type in the list on this page.
SYNTAX ERROR NEAR 'HERE' = Type of error and it was triggered near this word or symbol
Sometimes you'll see even more information given about the error in indigo. This is a breadcrumb trail starting at where the error occurred and working backwards to tell you what function(s) that line is in. This can be helpful because the real problem could be in one of the parent functions, not in the line that triggered the error.
Types of Errors
We have gathered a list of known error messages we have seen in PICO-8 and provided both a better description of what the error is, and some possible steps to finding solutions to fix them.
Error Message | Read How to Debug |
<eof>
|
Debug |
unfinished string |
Debug |
malformed number |
Debug |
attempt to perform arithmetic |
Debug |
attempt to concatenate field |
Debug |
unclosed ...
|
Debug |
'a' expected near 'b'
|
Debug |
unexpected symbol near 'a'
|
Debug |
attempt to call |
Debug |
attempt to index |
Debug |
End of File
"EOF" stands for "End of File" which means that PICO-8 reached what was expected to be the final end, but there was more code after that point.
Example:
function _draw()
if a then
if b then --errors here
end
end
end
end --extra end here
How to Debug: Find and remove one or more extra END
s. It may not be where the error points to, so carefully go through your code to match each END to its "opening" until you find the END that does not have a match.
Unfinished String
Strings must start and end with quotation marks, either double quotes ("string"
) or single quotes ('string'
). This error has detected a string that you either started or ended but has a missing quotation mark to the pair.
Examples:
name = "billy
name = billy"
How to Debug: Find and add the missing quotation mark matching the one shown in the error.
Malformed Number
"Malformed" means "created incorrectly" and refers to a number data type that it recognizes as trying to be a number but it is not able to resolve into a well formed number. Common causes could be using more than one decimal point, or attempting to concatenate (..
) incorrectly. If you try concatenating a string by starting with a number, it will also error, so it is better to put that number in a variable or quotes.
Examples:
num = 1.2.3
num = 1..2.."3"
num = 123.."abc"
How to Debug: This error usually does a good job about pointing directly to your problem. Find the buggy number and make it a true number.
Attempt to Perform Arithmetic
This error shows when something goes wrong when trying to do math, usually with variables that are not numbers. The full error will explain what the value is instead, such as "attempt to perform arithmetic on [variable] (a nil value)" which means that it cannot find that variable and it does not hold a number value. It might also say "(a string value)" even though PICO-8 will attempt to convert strings to numbers first, any string that cannot be converted will trigger this error.
Examples:
math = 1 + a
math = 1 + "a"
How to Debug: This error usually does a good job about pointing directly to your problem. Find the buggy variable and make sure what you are trying to do math with are all number data types.
Attempt to Concatenate
"Concatenate" means "to put together in a connected series, like a chain". This error means that something went wrong while trying to use the (..
) string operator, explained here. If you try to concatenate a variable that is nil, a boolean, or a function, then it will trigger this error. If trying to concatenate a number directly (not in a variable), then you must put the digits inside of quotation marks to make it a string first. On the other hand, if the variable you are concatenating is holding a number value, then PICO-8 will automatically first convert it to a string for you, which is why number variables can be concatenated.
Examples:
string = "abc"..a
string = "abc"..true
string = "abc"..print
How to Debug: Find the line where you are concatenating a string, and double check all of the values are strings already. You may need to use tostr()
to convert your value to a string before concatenating it.
Unclosed
An "unclosed..." error means that some block of code is not properly closed (ended). This error is specified to be one of these issues:
UNCLOSED IF | If statement does not have a matching end |
UNCLOSED FUNCTION | A function does not have an end |
UNCLOSED FOR | A for loop does not have an end |
UNCLOSED WHILE | A while loop does not have an end |
Example:
if a then
function b()
for c=0,10 do
while d do
How to Debug: This error usually does a good job about pointing to the correct problem, but you should double check, especially for nested blocks of code. Match each END "closing" to its "opening" to find the one that is missing and add it in the correct place. Proper code formatting through indentation will help make this search easier, and prevent you from making this mistake in the future.
Expected
This error tells you what word or symbol is expected near what part of the line of code. Certain key words or symbols go together to form proper code syntax (basically the grammar rules of the coding language). If statements usually require a "then". Loops usually require a "do". Tables require "{" and "}" and commas "," between values. Forgetting these are common mistakes that will trigger this error. Less commonly, it could say <name>
expected, which means there is a missing variable name that it expects.
Remember that "elseif" requires "then" even though "else" does not have a condition nor a "then" and only write one "end" for an "if" statement, no matter how many "elseif" are in between.
Examples:
if a end
--error: 'then' expected after if
if a then
elseif b
else
end
--error: 'then' expected after elseif
for i=0,10 end
--error: 'do' expected after for
table = { a,b c d }
--error: '}' expected near c
--missing commas
How to Debug: Start with where the error points and look for the word or symbol that it says it is expecting to find where that word or symbol is missing. Sometimes you do have what it expects in your code but it may expect it earlier than you have it, so the bug may be something else in between such as a table having the closing brace but missing commas.
Unexpected
This error is quite common because it covers many different possible bugs. In general, it tells you that a word or symbol is just in the wrong place according to the code's syntax (structure rules) but it could be either something is added unnecessarily, or something is missing that causes the next word or symbol to come earlier than expected. To avoid this error, it just takes a clear understanding of the syntax rules, and that comes from either a lot of reading, or a lot of practice. So if you are seeing this error a lot, it may be difficult to find the problem and fix it, but with more experience, you'll come across this error less and less.
Examples:
if then a=10 end
--missing condition
table =. b
--unnecessary symbol
How to Debug: Read through the code at the line the error points to, considering syntax rules for every word and symbol to find what is there unexpectedly or what is missing. Take the time to study and learn the rule that has been broken so you don't make the same mistake in the future. Often times, an experienced programmer can identify the problem quickly, so you can share your code and the error and ask for help, but don't just fix the code, take the time to understand the problem so you can identify it yourself next time.
Attempt to Call
This error means that the code tries to run a function ("call" it) but cannot find the function it is being asked to call. This can happen with mistyped function names, or calls to a function occurring before the function is declared. If you have any functions that you want to run during the initialization of your game, then make sure to put the call inside of _init() which will make sure that the functions are all declared before _init() gets run. If your call is outside of any function, it will try to run that before _init(). Understanding the order that your code is run is especially important when you start preparing multiple scenes.
Example:
a=10
a()
--a is not a function
b()
--b is not yet declared
function b() print("hi") end
How to Debug: Find all cases where you are trying to run the function and double check that it is spelled correctly. Then make sure that in the order of running your game, the function gets declared before you try to call it. Then make sure you are not overwriting the function between declaring it and calling it. Know that function names are no different from variable names in Lua, so it is important to avoid using function names as your variable names.
Attempt to Index
This error means that PICO-8 tried to find an element of a table but couldn't find either the whole table or the key in that table. It will usually state what data type it is when it is not able to access the table such as "attempt to index 'tbl' (a nil value)" or "(a number value)". Less commonly, the error may say "(for compound)" possibly meaning that a for loop is involved, but we are looking for more information on this specific error.
Examples:
a[1] = 10
--"a" is not defined yet
a = {1,2,3}
for b in all(a) do
b.health+=1
end
--"b" is not an inner table in "a"
for e in all(enemies) do
e.x+=1
end
e.y+=1
--"e" is not a table outside loop
How to Debug: Find the variable that it is trying to index and make sure that it is a table. Also make sure that the table is accessible where you are trying to retrieve a value from it. A common mistake is trying to use a local table created by for var in all()
loop, outside of that loop.
1540
29 Apr 2025
echo
This is a system for collecting and printing messages ("echoes"). It is useful for debugging or displaying multiple values during gameplay without cluttering the code, allowing for quick logging and dynamic feedback.
(This tutorial was written in collaboration with RB)
What's wrong with using print()
?
The problem with printing values while debugging, as you may have already experienced, is that most values you need to check are somewhere in your update function, and if you try to print them at that point to your screen, the prints just get erased by cls()
in the draw function. Alright, to solve that, you just need to make sure you print those variables somewhere in the draw function, but by the time those variables are printed, they may have changed values once or more times, so now it's a problem of needing to print the values exactly what they were, at certain points in your code.
To solve that, you could make some debug variables such as debug1, debug2, debug3,
and then set those variables to save the values at certain points in your code. Then down in draw you print each of those variables. But now you either don't have enough specific debug variables or you have too many cluttering up your code and you have to keep track of which ones are already being used, adding to your mental strain while hunting for a bug. Quite a hassle.
The echo system solves all of these problems so you can keep your time and attention on the actual debugging issues.
Is this better than using printh()
?
The most common suggestion for printing debugging messages is to use printh() which is a built-in function for printing to the console, outside of PICO-8. But the console is not automatically started with PICO-8 by default so there are extra steps to get that set up and working. If you are already using an external code editor then you may prefer to use this method. But if you like developing all within PICO-8 itself, or if are using the Education Edition, then the echo system here is a great way to keep things simple and print accurate values directly on screen.
Echo System Setup
To add this system into your game, simply copy the code below to declare the table and two functions, and you can paste it right at the beginning of your code so that you can easily find and remove it when your game is complete.
---------------------------debugging----------
-- echoes collection
echoes = {}
-- store a value to be printed
function echo(val)
add(echoes,tostr(val))
end
-- print all echoes
-- ...opt: c (text color, default: latest)
-- ...opt: x,y (print coords)
function print_echoes(c, x, y)
local cx, cy, cc = cursor() --pen_x, pen_y, pen_color
--set text position and color
cursor(x or cx, y or cy, c or cc)
for i=1,#echoes do
print(tostr(echoes[i]))
end
--erase all echoes
echoes = {}
end
-------------------------------------------------
Then make sure you call the print_echoes
function at the very end of your draw function so that it always prints debugging messages on top of anything drawn in your game.
function _draw()
... --all of your draw code
print_echoes() --just add this line
end
*** You can customize the print_echoes function with text color and position, or leave it on default which is whatever the cursor's last color and position is.
Lastly, wherever and whenever you want to print values to the screen as debug messages, simply write echo()
at that point in the code and include the variable you want to print and it will save the value of that variable as it was at that point in the code. You can also add a label to be printed, for example:
x = 10
function _update()
echo("x before = "..x)
x = x + 3
echo("x after = "..x)
end
For printing simple values, that is all you need. But you may find yourself wanting to print the contents of a table. Instead of looping through all the entries of the table and echoing their values, here is an extension of the echo system specifically for printing the (shallow) contents of a table at any point.
Simply pass a table and an optional label to this echo_tbl()
function at any point in your code, just like you would use the regular echo()
function. Don't forget to copy and add this function with the others at the start of your code.
-- optional: label (header caption)
function echo_tbl(tbl, label)
if type(tbl) == "table" then
add(echoes,"--")
add(echoes,"[ " .. (label or "unlabeled") .. " ]")
add(echoes,"")
--
for k,v in pairs(tbl) do
add(echoes,("+ " .. k .. ": " .. tostr(v)))
end
--
add(echoes,"--")
end
end
Debugging Tip!
Often times while debugging, you want to run your game, then stop or slow it down just before the bug happens so you can see the values and discover what is causing the bug. To do that easily, you can use stop() to exit a running game at a specific point so you don't have to try to time it by hand. You can use an if statement to determine when your game is getting close to the bug in order to stop it at the right time.
function _draw()
cls(1)
-- all your draw code
--debugging--
print_echoes()
if x>20 then
stop()
end
-------------
end
You can then advance the game frame-by-frame and take all the time you need to monitor your debugging variables like running the game in super slo-mo by using the frame stepping command. This should really help you narrow in on the bug and solve the issues fast and easy.
Echo System Explained
The Echo System uses 1 table and 2 functions:
echoes = {} |
An empty table to hold debug messages. |
echo() |
Adds message text to the echoes list. |
print_echoes() |
Prints all the stored values on the screen at specified coordinates and text color, then clears the list. |
With an optional third function:
echo_tbl() |
Adds table data to the echo list to easily print table data. |
First we create an empty table to hold all of the debugging messages:
echoes = {}
Then we will add values to that table with the "echo" function, making sure the value being saved is converted to a string data type with tostr(). You can start using this function anywhere in your code to record values exactly as they are at that point in the code to be printed at the end of the draw call.
function echo(val)
add( echoes, tostr(val) )
end
Then we print all of the messages from the echoes table with the print_echoes function.
function print_echoes(c, x, y)
local cx, cy, cc = cursor() --pen_x, pen_y, pen_color
--set text position and color
cursor(x or cx, y or cy, c or cc)
for i=1,#echoes do
print(tostr(echoes[i]))
end
--erase all echoes
echoes = {}
end
This custom print function has 3 optional parameters: c, x, y
. Those are for customizing the text color and position of the first printed line of debugging messages, your echoes. The first line of the function takes the cursor position and color to be used as the default values if you do not give the function any arguments. The parameters and default values are prepared this way so that you can call this function in 3 ways:
print_echoes() --default color and position
print_echoes(7) --set color, default position
print_echoes(8,10,10) --set color and position
After getting and using either the given arguments or the default cursor values, the function loops through the echoes table and simply prints each value. Finally, it empties the echoes table so that the next frame of your game can print all new values.
If you included the echo_tbl()
function, then you can call this function just like calling echo()
, but pass it an entire table instead of just a value. You can also include a header label to identify the table data easier in your debugging messages.
echo_tbl( player, "player table" )
The way that function works is it first checks to make sure that the first argument passed is actually a table so that it doesn't error when trying to get the table data. Then it adds a double dash just to separate the table data visually from any other echoes. If you included a label, then it will add that to the echoes, otherwise it will add "unlabeled" instead. Then it will add a blank string to echoes to create a gap between the label and the table data. Then it will loop through the table data, extracting the key and value pairs and add those together in a string as individual echoes with a colon in between. Finally, it adds another double dash to visually close the table in the echo output.
Here is what this player table would look like after echoing it using the code example above:
player | |
---|---|
x | 10 |
y | 20 |
sprite | 1 |
--
player table
x : 10
y : 20
sprite : 1
--
246
1 Jun 2025
.
.
Yep, just a dot in the command line.
A very helpful debugging tool, built into PICO-8 since version 0.2.0, this command lets you run your game for one single frame. It will call _update and _draw once, then stop the game and return to the command line.
While hunting for the cause of a strange bug, you will likely want to run the game and try to reproduce the bug. Sometimes that is enough to know how to fix it, while perhaps more often that isn't enough because everything happens so quickly and you need more precise information about what is happening. With this command, you can now run your game and approach the moment that the bug happens, then press escape to stop your game.
Once the game is stopped, you can use this command to resume the game but only advance by one frame. This will let you see what is happening in your game in slo-mo and take the time you need to view any debugging messages you print to the screen every frame (try the echo system for that).
PICO-8 also has a built-in shortcut to enter this frame-stepping command and run it a second time.
After you have used the command once, you can continue frame stepping in PICO-8 by simply pressing enter again and again to walk step-by-step through your game and read the debugging messages every frame.
This should really help you narrow down the causes of your bug until you find it.
107
1 Jun 2025