PICO-8 allows 65536 characters, which on one hand is a tight limit for some projects. But, on the other hand, we've seen amazing things from Tweet jam in 140 characters or fewer.
That made me wonder...can a whole PICO-8 game be written in 1024 characters (1k)? There are some impressive JavaScript 1k demos. Let's see what we can do!
Rules:
- Entire program source code lists as 1024 characters or fewer inside PICO-8, including comments.
- Must be a playable game, not just an animation.
- No limits on music, sprites, or map, since they don't count toward PICO-8's character limit.
This is my PICO-1k jam entry. The entire source code is 1024 characters in PICO-8, including the comment at the top. Arrows to fly, button (z on keyboard) to fire.
--top*burn a=48n=32k=64_={}camera(-k,-k)c=16x=0y=0t=0o=0g=0q,b,r,s,h=sqrt,btn,rnd,spr,sspr::a::l=t%8/4map(0,0,-k,-k,c,c)for j=3,k do z=j/4h(q(q(z))*c-l,1,k+k,1,-j*n,j,k*4*z,1)end l=l<1o=max(o-1,0)f=b(4)and o<n if f then m(r(3))o+=2 if(o>n)o=98 end i=l and o>n and s(124,-k,-40,4,1)or h(0,56,min(o,n),6,-k,-a),l and t>650or h(a,n,n-t/n,8,n,-a) i=b(1)p=24m=sfx if(i and x<c)x+=2 p=c if(b(0)and-k<x)x-=2 p=c if(b(2)and y<n)y+=1 p=k if(b(3)and-n<y)y-=1 p=74 s(86,x+8,a,4,2) for e in all(_)do e.x+=e.d e.z+=.1 j=e.d<0w=88z=4/e.z if(e.l==0or e.z>k)del(_,e) if(e.l)e.l-=1 j=r(2)>1goto e h(56,k,c,c,e.x*z+24*z,a*z,c*z,c*z,j)w=k if(f and max(abs(u/z-e.x-21),abs(v/z-e.y-8))<8)e.l=8m(3)g+=.75 ::e::h(0,w,56,24,e.x*z,e.y*z,56*z,24*z,j)end if(r(98)<1)d=sgn(r(2)-1)add(_,{x=r(n)-d*k-c,d=d,y=r(k)-a,z=1}) z=.7u=x*z+13v=y*z-8s(2,u,v) if(f and l)s(c,u*.9,v*z)s(17,u,y*z-5)z+=.1 s(38,x*z+10,y*z-2,2,1)z+=.1 s(46,x*z+14,y*z+1,2,1) s(p,x,y,6,3,i)s(240,-30,-41,g,1)flip()t+=1 if(t<999)goto a ::g::s(137+t%2*k,t%192-140,-n,7,1)flip()t+=1 goto g |
Here's the source with comments to make it more understandable:
-- topburn -- @casualeffects -- a pico-8 game in 1024 -- characters (this is the -- version with comments, which -- is larger!) -- -- common constants: -- k = 64 -- a = 48 -- n = 32 -- c = 16 -- -- common functions: -- q = sqrt -- b = btn -- s = spr -- h = sspr -- r = rnd -- m = sfx -- -- t = timer (frame count)/fuel -- x,y = plane position -- z = scale factor -- _ = enemy array -- p = plane sprite index -- i = right button (during plane code) -- j = flip sprite left-right -- o = gun overheat status -- f = true if firing -- u,v = reticle coords -- e = enemy -- w = enemy sprite y -- l = modulo counter (for background) and blink (for hud and bullets) -- g = kills -- d = temp var -- -- enemies: -- x,y,z = coords -- l = life -- -- use 1<0 for "false" and 1>0 for "true" -- use "p=a and b or c" for "if a then b else c" -- any letter > f can be run against a number to start a new statement -- += and single-line "if" require a newline --background a=48n=32k=64_={}camera(-k,-k)c=16x=0y=0t=0o=0g=0q,b,r,s,h=sqrt,btn,rnd,spr,sspr::a::l=t%8/4map(0,0,-k,-k,c,c)for j=3,k do z=j/4h(q(q(z))*c-l,1,k+k,1,-j*n,j,k*4*z,1)end -- hud l=l<1o=max(o-1,0)f=b(4)and o<n if f then m(r(3))o+=2 if(o>n)o=98 end -- blinking gauges p=l and o>n and s(124,-k,-40,4,1)or h(0,56,min(o,n),6,-k,-a),l and t>650or h(a,n,n-t/n,8,n,-a) --player shadow + flying code i=b(1)p=24m=sfx if(i and x<c)x+=2 p=c if(b(0)and-k<x)x-=2 p=c if(b(2)and y<n)y+=1 p=k if(b(3)and-n<y)y-=1 p=74 -- plane shadow s(86,x+8,a,4,2) --enemies for e in all(_)do e.x+=e.d e.z+=.1 j=e.d<0w=88z=4/e.z if(e.l==0or e.z>k)del(_,e) if(e.l)e.l-=1 j=r(2)>1goto e -- explosion h(56,k,c,c,e.x*z+24*z,a*z,c*z,c*z,j)w=k if(f and max(abs(u/z-e.x-21),abs(v/z-e.y-8))<8)e.l=8m(3)g+=.75 ::e::h(0,w,56,24,e.x*z,e.y*z,56*z,24*z,j)end -- new enemy if(r(98)<1)d=sgn(r(2)-1)add(_,{x=r(n)-d*k-c,d=d,y=r(k)-a,z=1}) -- player reticle + bullets z=.7u=x*z+13v=y*z-8s(2,u,v) if(f and l)s(c,u*.9,v*z)s(17,u,y*z-5)z+=.1 s(38,x*z+10,y*z-2,2,1)z+=.1 s(46,x*z+14,y*z+1,2,1) -- player plane + kills s(p,x,y,6,3,i)s(240,-30,-41,g,1)flip()t+=1 if(t<999)goto a -- game over ::g::s(137+t%2*k,t%192-140,-n,7,1)flip()t+=1 goto g |
As you can see, I took advantage of some funny aspects of the parser. Letters that unambiguously are not part of a hexadecimal number can be jammed right against a number to save the whitespace...except for += and similar operators, which oddly require a space at the end. Single-line IF statements require a newline at the end of course, but many other statements do not.
In a few places I used the fact that AND and OR operators can work with any value in PICO-8 to trigger sprite drawing only in certain circumstances.
The sprite sheet is specifically laid out to minimize the length of numbers needed and allow some funny math formulas to work. Unfortunately, I couldn't save enough characters to afford to play background music.
[Please log in to post a comment]