What an emotional and powerful speech! I can’t wait starting my first game on pico 8 on GGJ2020. I have been beating about the bush for half a year, sometimes I was very busy at work, sometimes no energy on weekends, but it’s time! all games and community of pico-8 motivate me and oust to create a small game too. Thank you!
PICO-8, motivation, and value
Making a game
I've been trying to make games for a quite a while! Typically my pattern is:
- Get excited about an idea
- Work furiously building an engine for said idea
- Start fleshing out the engine in all directions, trying to plan for anything and everything I might want
- After weeks of programming, discover some large design flaw in my engine
- Start rewriting game with a new paradigm or in a new language or with new tools
- Finally or nearly finish the engine; now time to start making the game
- Completely lose motivation because I'm burnt out and I've forgotten what made me excited about the idea in the first place
Maybe some day I'll finish my Zelda Randomizer (before the ROM-based randomizers were a thing!), or my Cave Noir-inspired roguelike, or my competitive text-based Wumpus game, but it seems unlikely at this point!
PICO-8 is a self-contained "fantasy console". It has certain specifications that all games made in it need to adhere to. I was initially attracted to PICO-8 because of its constraints. It immediately solves some problems and makes a lot of decisions for you. I don't need to agonize what my screen size or aspect ratio should be. It's 128x128. I don't need to pick a palette. It's these 16 colors. How will I make music and sfx and graphics? There's a music tracker and graphics editor built in! How will I distribute my game? You can make executables for any platform, and you can target HTML5.
I was also attracted to the community around it. All the code and data for the carts is inherently open source, and the community is helpful and they all iterate on each others' ideas. There are many cool games and demoscene projects in Pico-8. It's really fun to try to get the most out of a platform with heavy constraints.
For my project Heat Death, I resolved to take the opposite approach I normally take: instead of planning everything out and making a comprehensive engine, I instead just sort of hacked everything in. Nothing was planned, and I took the path of least resistance while programming it. If a certain feature started to get hard to implement, sometimes the path of least resistance was to refactor and rewrite the code. When it was easy to share code between enemies or objects I shared code. When it was hard, I didn't.
Hack it in
There was never an insurmountable problem to solve, because the structure of my game was inherently simple. Game development (at least for me) is a very fluid process, and it's a fool's errand to try to create a structure that will support everything you want to do in the future.
I'm always reacting to what I just built, iterating on what worked, what didn't work. With this "hack it in" mindset I was able to prototype ideas very quickly. I wasn't immediately getting discouraged upon realizing I would need to completely redo how something worked in my game.
The fine print
In addition to the player-facing constraints (graphics, sound, etc), PICO-8 also features some rather strict development constraints which are somewhat invisible in the final work, and I had (and still have!) a very complicated relationship with these.
- PICO-8 limits the number of operations you can do per frame. This is effectively like a CPU limit.
- PICO-8 carts must fit into a compressed size of 32KB.
- You are limited to 8192 "tokens" per cart. A token is a variable, a keyword, a pair of parentheses, basically every element you use to write code. This sort of represents roughly how complicated your code is.
If compared to developing a game on a modern system, these constraints are incredibly harsh. I went in with the expectation that my game would have to have an extremely small scope to satisfy these constraints. I think this aspect of the constraints is great, because the main thing that stops my projects from being finished is scope creep. I focused on a Robotron-style arcade shooter, because arcade games tend to be fairly straightforward and focused, without too many superfluous elements.
Of course, as I started working on the game I got more and more excited about how it was turning out, so I naturally had growing aspirations for it.
Rabbit hole 1
The first roadblock I ran into was the CPU limit. I wanted way more enemies on screen than my code was currently supporting. My framerate was dropping to unacceptable levels when a decent number of enemies were on screen at once. Was PICO-8 just not capable of handling this many collisions at once?
Well, the answer was "actually, no", but it was very very complicated! I spent hours of time iterating on my code, doing research on the snappiest ways to do things in Lua, caching things, unrolling loops, and completely obfuscating my "simple" code. But hey, once I was done, my game supported way more enemies on screen at once than I would need.
To keep this snappiness, this actually ended up extending to all collisions in the game. Instead of solving collisions generally (which was too slow), I had to apply problem-specific optimizations for each "type" of collision in my game.
- Enemy to player bullet collisions
- Player to enemy and enemy bullet collisions
- Player to pickup collisions
- Enemy and player to wall collisions
Every one of the above cases has a bespoke collision solution. And while it took more code size and tokens, it was indeed fast!
Rabbit hole 2
Tokens. Oh my god, tokens. While my code was now running at a snappy clip, it was taking up way more tokens than before. But I planned all these beautiful features! How will I fit it all on the cart?
My first solution was to split the menu into its own cart. PICO-8 carts can launch into other carts nearly seamlessly, at the cost of about a 1 second loading icon. By splitting the menu into its own cart, I effectively gave myself much more room for the game on the game cart. This also allowed me to flesh out a lot of menu features, which is why the game has an intro, all the different modes, color customization, help & credits screens, highscores, etc.
This worked for a while but
Rabbit hole 3
it never ends with these tokens! To make my game interesting at a higher level of play, I wanted more variety, but that variety came at the cost of tokens. I wanted each level from 1-10 to have different enemy ratios and variations. I wanted the player to have 3 usable abilities to further increase the skill ceiling. As hard as I tried, I just could not get it to all fit.
To remedy this, I started looking up token saving tricks. Often there were ways to express the exact same code in a fewer number of tokens, at the cost of legibility and clarity.
I spent hours and hours and hours reading over my code line by line, applying these optimizations everywhere I could manage. Every time I made a change, I have to go back through the code yet again and eek out more tokens. But it ultimately still wasn't enough!
Finally, I realized that I could save tokens by storing data in strings. A string could be an arbitrary length, but it only cost one token. By writing some string parsing code, I could effectively store a lot of data in strings, relieving the pressure of the token count (at the cost of compressed cart size!)
At this point, each simple feature I wanted to add would take hours. This change resulted in too many tokens, so I had to do another token optimization pass. This change made me hit the cart size limit, so I had to do get rid of long variable names and white space. I finally conceded and narrowed down exactly what features I thought were most important and focused on those,
Despite myself and my stubbornness to solve this token and size "problem", I did finally learn the lesson PICO-8 was trying to teach me. I should value my time! PICO-8 taught me that there was a personal time cost to every feature I implement. Instead of being a perfectionist and tweaking things that mostly worked already, I should focus on the big picture high impact features.
In retrospect, I have no idea how this was a revelation for me, but it was! It completely changed how I thought about game design. My perfectionist ass shouldn't be spending all my time on the smallest of details. Programming on a modern system, those details would only cost me "time", but in PICO-8 every change costs tokens and cart size in addition to time. This additional cost also effectively increased the time it took to implement them, which helped calibrate me to where I should have been to begin with.
Was it worth it?
PICO-8 is not for everyone, but I think it works exceptionally well for the people it is for.
I think I accidentally found out PICO-8 was for me. I initially viewed the constraints as a fun puzzle and a challenge. Later, I viewed the constraints as a supreme annoyance and extremely demotivating. I was on the verge of giving up due to these "artificial" roadblocks PICO-8 was throwing at me. It was only once I learned the correct lesson -- that my time is important, and I should spend it wisely -- that I finished making a game. Maybe now that I've "learned" that lesson, I can ditch the frustration and make a game in something less actively hostile?
Maybe, but working in PICO-8 is invigorating!
Log in with itch.io to leave a comment.
Nice write up! ☺️ After some pico-8 games you learn how to hold back on features and scope, sometimes for the good but sometimes for the worse. That is just its nature.
This is spot on. Ran into exactly the same limitations and resorted to string and tile map encoding for my Boulder Dash demake, "Boulder Run" since there were so many levels to map.
I actually found it quite relaxing at the end of each coding session to go through the code I'd written and refactor it to get the token could down a little.
Was it worth it? of course :)