Saving characters


My first entry to Tweet Tweet Jam (and any game jam for that matter) taught me a lot about squeezing the most into 560 characters of PICO-8 code. I enjoyed it enough that I'll be sure to try again next time, but fore-armed with the following knowledge.

I'd be very grateful for any feedback, additions or corrections from anyone reading and especially from those (many) devs out there who know more about this than I do.

Disclaimer

Do _not_ consider these tips as suitable for general development - on the whole they're really bad things to do that will make your code un-readable, more fragile and just, well, don't okay?

The Tips

  • Use single character variable names. PICO-8 respects case for these so v and V are different variables. It'll prob make it easier for you if you stick to some kind of convention for when you use what if you can.
  • Don't put spaces around arithmetic operators or after commas etc.
  • Comments are a no-no
  • PICO-8 is very forgiving when it comes to stringing statements together. There's no need for a character after a bracket or number before the next statement. The following are legal, both with two separate statements each:
x=f(z)y=3
x=(1-z)*5y=10
  • To take advantage of this, try to order statements to end on a bracket or number:
x=y*(z-1) vs x=(z-1)*y
  • Save on brackets entirely by knowing the operator precedence and not using them redundantly.
  • The shortest loop, even with the flip() statement seems to be:
::A::flip()goto A
vs
while 1do flip()end
function _draw()end

Note: this only allows 30fps for your game.

  • Use short ifs
if(x<7)v=2 vs if x<7then v=2
11 (with \n) vs 15 (with space/\n)
  • This forces a whitespace character (I use a newline) after them, but doesn't always need the same to the left. I couldn't work out exactly when that was needed so sometimes the following works
x=12y=15if(b)z=1

But might need to be:

x=12y=15
if(b)z=1

So try both, I guess (anyone know?).

  • These shortened ifs are sometimes shorter even than the following form if you don't need the "else":
a=b and x or a   vs   if(b)a=x
since   "a=b and x" doesn't work.
  • If you do need an else and can't use the bool/arithmetic trick above then consider whether you can execute what you have in your else clause unconditionally  and override it with what's in the conditional clause to save the ' else' characters:
a=c+B(z)
if(b)a=x
[17 chars]
if(b)a=x else a=c+B(z)
[23 chars]

Note: this obviously means PICO-8 executes calculation unnecessarily, since the value in a is immediately overridden, but, at least for this purpose and in my experience, characters are much more precious than performance. Even inside a for loop over a large number of values it's quite possible that you can get away with repeatedly assigning values etc. without getting anywhere near performance problems and if it saves characters then it's probably worth it. As with any development DYOP (do your own profiling) and decide.

  • Some statements, no matter how you try, will need a white space character after them. I found using a new line meant I could  see how to re-order code to minimise how many times I needed to do this e.g.
a=2b=f(34)
if(y<10)X(4)
c=x
d=12

becomes

a=c+B(z)d=12c=x
if(y<10)X(4)
  • Unintuitive order of calculation can sometimes save characters. This is how the screen clear ended up being halfway through my code rather than at the top, like you'd expect.
  • Favour operators of a single character like < or > over ==, <= or != etc.
  • If you can do logic with integers instead of booleans then you can use |, & etc. instead of and, or etc. and save the extra characters. 
  • For fractional values, leading zeros aren't needed, but try refactoring operators as well:
x*=0.5
vs
x*=.5
vs
x/=2
  • To save PICO-8 tokens, "batching" assignments is beneficial, but doesn't work so well for saving characters:
a,b,c=1,2,3
vs
a=1b=2c=3

It even has the advantage of letting you do things like:

a=f(2)b=a*2
  • Re-name functions if you use them enough - there's a tipping point, depending on the length of the function name that dictates when this is worth doing.
C=cls C(1)C(2)C(3)C(4)
vs
cls(1)cls(2)cls(3)cls(4)

4 uses for a 3 character long function definitely is worth it. If you can find a way to save the space after "cls" in the top line then you can save a character even with only 3 uses. 

  • Use the short form of print: ?
print(s,0,10,12)
vs
?s,0,10,12
  • Assign long values to variables and re-use if you can. For example, PICO-8 has a resolution of 128x128 so you could do something like:
d=127
...
x+=v%d
y+=w%d

I did this quite a lot in my game. Incidentally, & can sometimes substitute for % (positive&power of two-1) and has higher precedence so can save brackets.

  • I used a string of hex values and a for loop to dump those values into sprite memory which was shorter even than directly inserting the values using poke4
  • If you can make your game without sprite data then do so though - it was a bad idea and ate 100+ characters before I even started on the rest of the program.
  • Initially when the player lost in my game I had a bunch of variables reset in the conditional part of the if statement that checked for collision. I eventually realised it was cheaper to re-initialise the game entirely.

I was amazed at how much I squeezed into 560 characters after using these tricks and how many places they could be used. I can see places to save even now - see if you can spot any, k?

I was even more amazed when I saw what other people had done. Next time I'm determined to aim a bit higher - but no doubt I'll still be just as amazed..

Comments

Log in with itch.io to leave a comment.

what a great guide! I learned many tips from you, thanks! Will look forward to squeezing more out of my 560 chars next tweettweetjam ;)