Code Trip
  • Blog
  • Archive
  • Projects
  • Portfolio
  • CV

Tweetjam

18/8/2016

0 Comments

 
The PICO-8 Tweetjam is brilliantly simple: make a PICO-8 cartridge that can fit into a single tweet (140 characters). Unlike a typical game jam there is no deadline for submissions; the jam started on Twitter and the PICO-8 forum in late June and people continue to make cartridges for it now. Here are my submissions. If I make more in the future I'll update this post. Edit​: I did!

No. 1: Circle Sweep

Picture

​
29/06/2016. ​134 chars. This is just drawing a line between points on two circles which rotate at different rates.
cls()
t=0
c=1
while 1 do
m=64
x=30*cos(t)
y=30*sin(t)
z=60*cos(1.5*t)
w=60*sin(1.5*t)
line(m+x,m+y,m+z,m+w,c)
t+=0.00003
c+=0.0003
end


​No. 2: Circle Sweep 2

Picture

30/06/2016. 129 chars. This is a modified version of my first cart which tweaks the parameters a bit. The big change is obviously the kaleidoscope effect, which is what that poke does.
poke(24364,7)
t=0
while 1 do
x=20*cos(t)
y=20*sin(t)
z=50*cos(0.3*t)
w=50*sin(0.3*t)
line(30+x,30+y,30+z,30+w,t*2)
t+=0.00003
end


​No. 3: Curtain

Picture

04/07/2016. ​140 chars. The version which is all on one line is the true submission, there wasn't room for newline characters! The multi-line version is just to make the code more legible. This was inspired by the vertical raster bars demoscene effect.
t=73p={t}n=128 function _draw()cls()for i=n,2,-1 do p[i]=p[i-1]x=p[n-i]or 0rect(x,n-i,x+1,n,i)end t+=0.02 p[1]+=sin(t)+sin(t/2)+cos(t/3) end
Here's a multi-line version for clarity (though it's no longer tweet sized!):
t=73 p={t} n=128
function _draw()
cls()
for i=n,2,-1 do
p[i]=p[i-1]
x=p[n-i] or 0
rect(x,n-i,x+1,n,i)
end
t+=0.02
p[1]+=sin(t)+sin(t/2)+cos(t/3)
end


​No. 4: Interdimensional Cliffs

Picture


​04/07/2016. 135 chars. This is the exact same as No. 3 Curtain but without the call to cls(), which clears the screen.
t=73p={t}n=128 function _draw()for i=n,2,-1 do p[i]=p[i-1]x=p[n-i]or 0rect(x,n-i,x+1,n,i)end t+=0.02 p[1]+=sin(t)+sin(t/2)+cos(t/3) end
Multi-line version for clarity:
t=73 p={t} n=128
function _draw()
for i=n,2,-1 do
p[i]=p[i-1]
x=p[n-i] or 0
rect(x,n-i,x+1,n,i)
end
t+=0.02
p[1]+=sin(t)+sin(t/2)+cos(t/3)
end


​No. 5: 3D Auto Pong

Picture
05/07/2016. 139 chars. At first this was going to be interactive but I couldn't fit player input in anything near 140 characters, so it ended up being automated (there is a bat at the top too, if you look closely). The size and color of the ball are based on the y coordinate to create a 3D effect. The x coordinate follows a sine wave to simulate bouncing off the sides of the screen, while the y coordinate follows an absolute sine wave so that it spends less time at the bottom of the screen and more at the ​top, which adds to the depth.
Here I'm also using a label ::L:: and goto statement in conjunction with flip() which swaps the back and front screen buffers; this is a trick I learnt from other tweetjam carts and uses less characters than a while/do loop with calls to cls().
n=127 t=0::l::cls()t+=0.005 x=64+64*sin(1.6*t)y=n-n*abs(sin(t))line(x-2,0,x+2,0,1)circ(x,y,y/10,8+y/42)rect(x-25,120,x+25,n,12)flip()goto l
Multi-line version for clarity:
n=127 t=0
::l::
cls()
t+=0.005
x=64+64*sin(1.6*t)
y=n-n*abs(sin(t))
line(x-2,0,x+2,0,1)
circ(x,y,y/10,8+y/42)
rect(x-25,120,x+25,n,12)
flip()
goto l


​No. 6: Chars

Picture
05/07/2016. 138 chars. One of the many awesome things about the PICO-8 is that it's creator zep hides undocumented bonus features in for the community to find. The kaleidoscope effect from No. 2 is one example, the wide characters here are another. Another trick I learnt from other carts is that in Lua you can assign functions to variables (r=rnd). Because I call the random function rnd() 4 times here (20 chars) I get a saving by assigning a reference to rnd to the variable r and then calling that instead (17 chars).
a="\128\132\133\134\135\136\137\138\140\141\143\144\146\147\150\152\153"r=rnd::l::i=r(#a)print(sub(a,i,i),r(122),r(124),r(16))flip()goto l
Multi-line version for clarity:
a="\128\132\133\134\135\136\137\138\140\141\143\144\146\147\150\152\153"
r=rnd
::l::
i=r(#a)
print(sub(a,i,i),r(122),r(124),r(16))
flip()
goto l


​No. 7: A Nice Day Out

Picture


​05/07/2016. 138 chars. My first tweetcart which exits after completing. Generates a randomised sunny field with a little house.
p=print r=rnd cls(3)rectfill(0,0,127,50,12)p("\143",20,20,10)for i=1,50 do p("\149",r(120),49+r(78),8+r(4))end p("\138",r(119),45+r(80),6)
Multi-line version for clarity:
p=print r=rnd
cls(3)
rectfill(0,0,127,50,12)
p("\143",20,20,10)
for i=1,50 do
p("\149",r(120),49+r(78),8+r(4))
end
p("\138",r(119),45+r(80),6)


​No. 8: People

Picture
Picture
05/07/2016. 140 chars. This is my favorite and was the hardest to fit into a single tweet. It constantly prints random people made up of combinations of overlapping wide characters. The body character is a person or a star, while the head is an alien face, square face, ball or house. It was inspired by the awesome tweetcart Tileset Maker by Alberton. The ? syntax is unique to PICO-8 and is shorthand for the print function (another trick learned from other tweetcarts).
h="\130\134\138\140"b="\137\146"r=rnd::a::for x=0,96,8 do c=1+r(15)i=1+r(4)j=1+r(2)
?sub(h,i,i),x,117,c
?sub(b,j,j),x,121,c
end
?"\n"
goto a
Splitting the first line up for clarity:
h="\130\134\138\140"
b="\137\146"
r=rnd
::a::
for x=0,96,8 do
c=1+r(15)
i=1+r(4)
j=1+r(2)
?sub(h,i,i),x,117,c
?sub(b,j,j),x,121,c
end
?"\n"
goto a


​No. 9: Error

Picture
05/07/2016. 140 chars. A fun one inspired of course by the weird thing that old versions of Windows often did when programs crashed. This does actually use mouse controls on PICO-8, which is yet another secret feature found by the community. I had to cheat a little bit by drawing the cursor as a sprite, so this effect isn't pure code. It works simply by not clearing the screen each frame.
poke(24365,1)::a::x=stat(32)-25y=stat(33)+2rectfill(x,y,x+50,y+8,12)rect(x,y,x+50,y+8,1)y+=2
print("error",x+2,y,7)spr(1,x+25,y)flip()goto a
Multi-line version for clarity:
poke(24365,1)
::a::
x=stat(32)-25
y=stat(33)+2
rectfill(x,y,x+50,y+8,12)
rect(x,y,x+50,y+8,1)
y+=2
print("error",x+2,y,7)
spr(1,x+25,y)
flip()
goto a


​No. 10: Error Sprite

Picture


​05/07/2016. 126 chars. Based on No. 9, here I'm cheating a lot​ just for fun. The whole window is pre-drawn in the sprite bank.
poke(24365,1)
palt(0,f)
palt(14,1)
::a::
x=stat(32)
y=stat(33)
if(stat(34)>0)sspr(8,0,47,17,x-27,y-2)
spr(7,x,y)
flip()
goto a


No. 11: Punishment

Picture
25/09/2016. 140 chars. Writing lines on a chalkboard as punishment. Prints one character per frame then moves to the next line once complete. Once it reaches the bottom it just starts writing over the existing lines, meaning it visually does nothing more but without actually exiting the program, because that makes the terminal reappear.
s="i must obey the rules"i=1y=4
cls(3)rect(0,0,127,127,4)function _update()m=i%(#s+1)print(sub(s,m,m),m*4,y,7)i+=1
if(m>=#s)y+=6
y=y%120
end
Multi-line version for clarity:
s="i must obey the rules"
i=1 y=4
cls(3)
rect(0,0,127,127,4)
function _update()
m=i%(#s+1)
print(sub(s,m,m),m*4,y,7)
i+=1
if(m>=#s)y+=6
y=y%120
end


​No. 12: Zoom Counter

Picture
25/09/2016. 139 chars. Counting up from 1 and zooming each number. The way this works is by first printing the number to the screen, then copying that section of graphics memory into the spritebank memory (at sprite 0), then using sspr to print that area of the spritesheet back to the screen while stretching it over time. I had to use a lot of tricks to make it fit!
n=1palt(0,z)::a::cls(n-1)
?n,0,0,n
memcpy(0,24576,512)t=0::b::cls(n-1)sspr(0,0,8,8,64-t/2,64-t/3,t,t)t+=4 if(t>128)n+=1 goto a
flip()goto b
Multi-line version for clarity:
n=1
palt(0,z)
::a::
cls(n-1)
?n,0,0,n
memcpy(0,24576,512)
t=0
::b::
cls(n-1)
sspr(0,0,8,8,64-t/2,64-t/3,t,t)
t+=4
if(t>128)n+=1 goto a
flip()
goto b
The first thing of note is the call to palt(0,z). By default black (color 0) is treated as transparent by functions such as sspr. This call makes black not transparent so that when we copy black text to the spritebank we can print it back to the screen. Rather than pass 'false' I pass 'z', which is an uninitialized variable and is therefore 'nil' which is equivalent to 'false'.

I have two different labels ::a:: and ::b:: which split the program into 3 sections. The first section (before ::a::) is only executed once; the second section (::a:: to ::b::) is executed at the start of each number; the final section (after ::b::) is executed every frame.

cls() clears the screen to the given color (or black/0 if no color is given). The ? syntax is shorthand for the print function and prints the number n to the screen at (0,0) with color n. There are 16 colors in PICO-8 (0-15) but if you pass in other numbers it will automatically wrap to the correct color, so color 16 is color 0, 17 is 1 etc. So n just keeps counting up and we print text of color n onto a screen of color n-1.

Now we copy the portion of the graphics memory representing the first 8 rows of pixels on the screen into the start of the spritebank memory. The addresses are written in decimal rather than standard hexadecimal because it's shorter. Address 0 is the start of the sprite bank and address 24576 (0x6000) is the start of the screen. One byte represents 2 pixels since with 16 colors each pixel only needs 4 bits. At a resolution of 128x128 that means 64 bytes per row and 512 bytes for 8 consecutive rows, which is the height of a sprite (sprites are 8x8).

The printed number is now in sprite 0 so we can finally start rendering that to the screen. The position starts in the middle of the screen (64, 64) and both x and y decrease as the size (i.e. time) increase, which keeps it centred. Only 2 characters will fit in an 8x8 sprite so unfortunately it won't quite work above 99. Since we copy whole rows of pixels, larger numbers will actually be copied into the spritebank, I just had no characters spare to stretch more than a single 8x8 sprite.

The scaling is always even so it stays nice and smooth, and once large enough we reset and move on to the next number. Finally we call flip() to swap the front and back buffers to avoid flickering and to slow the whole thing down. There's a lot going on for just 140 characters!


​No. 13: Pyramids

Picture
30/09/2016. 132 chars. This one started out as a general scanline triangle rasterizer. While reducing the character count I made the bottom vertices always use the same y coordinate, then tried centring the top vertex. I liked it so I added color, translated to the bottom centre and even found room for button input to control the generation.
n=128::s::h,w=rnd(n),rnd(n)flip()cls()for y=0,h do
x=w*y/(2*h)line(64-x,n-h+y,64+x,n-h+y,4+11*(y%2))end::t::
if(btn(4))goto s
goto t
Multi-line version for clarity:
n=128
::s::
h,w=rnd(n),rnd(n)
flip()cls()
for y=0,h do
x=w*y/(2*h)
line(64-x,n-h+y,64+x,n-h+y,4+11*(y%2))
end
::t::
if(btn(4))goto s
goto t
0 Comments

    Author

    Connor Halford. Studied Computer Games Technology at Abertay, worked as a Games Programmer at MediaTonic, now working as a Programmer at Climax Studios.
    ​

    Useful Sites

    hilite.me converts source code into formatted, embeddable HTML without the need for CSS or Javascript.

    tablesgenerator.com performs a similar task as hilite.me but for tabular data.

    Archives
    All posts

    June 2017
    December 2016
    September 2016
    August 2016
    June 2016
    May 2016
    April 2016
    February 2016
    January 2016
    October 2015
    September 2015
    August 2015
    June 2015
    May 2015
    March 2015
    February 2015
    January 2015
    December 2014
    September 2014
    August 2014
    July 2014
    March 2014
    February 2014
    August 2013
    June 2013
    December 2012

    Categories

    All
    Advice
    AI
    Algorithms
    AMPS
    Audio
    Boost
    Box2D
    Coursework
    DirectX
    Flash
    Game Boy Advance
    Game Jam
    Graphics Programming
    Honours Project
    Maths
    Nonograms
    Oh God Why
    OpenGL
    PICO-8
    Pixel Art
    PlayStation 4
    PlayStation Vita
    Procedural Generation
    SFML
    Shaders
    Spirit Shift
    Twine
    Unity
    XAudio2
    Year 1
    Year 2
    Year 3
    Year 4

    RSS Feed

Powered by Create your own unique website with customizable templates.