Pico-8

Caoimhe

I exhibited at a showcase for local game makers yesterday. It was the first time I had done something like that and it was extremely fun and utterly exhausting. Working on games is an occasionally hobby; I don’t intend to make it my job and I haven’t worked on any game projects since the game jam last year, but I dusted off Snolf Robo Blast 2 and Conway’s Garden and set them up with some controllers for people to try out.

Someone “enjoying” Snolf.

I had not thought about how exhibiting these would work before the event but I quickly realised that I was going to have to give a lot of context to people as to what they were playing. The vast majority of people attending never heard of Sonic Robo Blast 2 before so I had to give a quick rundown to everyone on what it was and sometimes the concept of fangames and mods.

Even with that explained, though, it became apparent how awkward it was to try to convey what the mod is doing when people seeing it do not have a context of the base game and how the mod is creating an experience on top of that. They are coming in and seeing and playing this game for the first time and expecting it to be a coherent whole, not this deliberate awkward layer on top of a base game. You don’t have the context that the joy in it is that you are playing the game “wrong”, layering a control scheme and method of play that the world was not intended for. Many people when seeing it as a golf-type thing started looking for a hole or guidance on where they are shooting for. The levels have a fairly legible linear structure when played normally, but when you have never seen them before and can freely shoot yourself much farther and higher than the levels for designed for, bouncing every which way, it is become very difficult to parse the structure of the space. More than one person suggested there should be guiding arrows of some sort to help.

Some people, though, did gel with it straight away and were delighted by blasting Snolf around, which was really nice to see. I was quick to give credit to the SRB2 team for the game itself and Dr. Melon for the concept. A line I fell into saying that got a laugh from a lot of people is that “all I did was make the controls worse.” A lot of people also got a kick out of it when I pointed out that the game was technically an extremely heavily modified version of Doom. Some people did have more of a concept of an antigame and compared it to QWOP and Getting Over It when I tried to explain the awkwardness of it not being entirely unintentional and the other game makers there generally got it and found it interesting. There were a few parents who brought children, including a Sonic fan or two, and they gravitated over to it being one of the more brightly coloured, exciting looking things on display, only to get pretty frustrated with it. For the kids at least I did quickly quit back to the main menu and restart the game with normal Sonic so that they could have a bit of fun trying it out and gave on the details of SRB2 to their parents if they were interested in it, pointing out that it was free. I think if exhibiting it again it would be useful to have a second computer set up with the unmodified version of the game, both to give context and to allow any child who sees Sonic and gets excited to play something that would actually be fun for them.

Similarly for Conway’s Garden I had to let people know that there wasn’t really any goal or point to it and it was more of a piece of art and a challenge to make something in a tiny amount of code. I had the code open in a second in a second window to the side so people could see how small it was for themselves. A lot of people, quite fairly, lost interest in it quickly, but some people were fascinated by the highly condensed code and the idea of tweetcarts and Pico-8 itself and a surprising number of people were already familiar with and recognised Conway’s Game of Life.

There was one man in particular I had a lovely chat with who was unfamiliar with games generally (he had to ask to clarify if “mods” was short for “modifications”) but enthusiastic about discussing the things on display as art. He said the mix of chaotic generation with the player’s simple, deliberate movements in Conway’s Garden reminded him of Joseph Beuys’s I Like America and America Likes Me and immediately recognised the Sisyphean nature of Snolf.

I don’t know if I will do anything like this again any time soon (and I won’t be working on anything new to show for the moment) but I had a great time and met some very cool people.


Caoimhe

Yesterday I took part the Cork Game Jam which was the first in-person game jam I’ve taken part in and my first time diving back into game programming in a few months and Pico-8 programming in a few years.

The theme—“myth”—was announced at ten and the pizza arrived for the after party at around four, which gave me about six hours to derust and bang something out. It was exhausting and stressful but also a lot of fun. Here’s the result:

Control with , and

The theme being myth immediately reminded me of an idea I had years ago based on the Epic of Gilgamesh, one of the oldest pieces of literature that we have a record of. There exists no complete copy of it. What we have of it is an amalgam of fragments from various damaged cuneiform tablets.

My concept is an adaptation of Gilgamesh, probably a sidescrolling action platformer, that uses the aesthetics of corrupted data to fill in for the missing sections of text. Within the six hour window I managed to get a sample of that core idea implemented, though admittedly little else.

So that I wouldn’t have to do everything from scratch I used Matthew Hughson’s platformer starter kit as a base and started making modifications to the sprites and speed values to get more in line with my concept, using Castlevania sprites as a bit of a reference for the walk cycle initially.

I spent far too long getting an attack animation working before I realised I would probably not have time to implement any sort of combat. But its presence at least speaks to setting up an expectation of what the game might involve before you end up running into the faux-corrupted mess it actually is, or within the metafiction of the premise what the game once was before most of it was damaged and lost.

The other thing I added is, of course, the scrolling text taking up the top part of the screen, consisting of the start of the text of tablet 5 of the epic, taken from Maureen Gallery Kovacs’ translation. It starts out fairly normal and then getting more and more broken as it gets to the parts of the poem that are lost.

Within the code these are represented by lines of hashes. I wrote a text drawing function that, when it encounters a hash, draws random data from the spritesheet (from specifically selected sprites in it, not the entire thing) over it, mimicking the aesthetics of famous bugs such as glitch pokémon.

Ideally the progress of the broken text would correspond to the player discovering the broken nature of the game, but it just scrolls at a constant rate with a lot of normal text up front and there is not that much in the way of level so if a player simply walks to the right they will outpace it.

In a more full implementation of this idea the game could perhaps corrupt dynamically as parts of the text are reached, simulating live memory corruption. Or perhaps the scrolling text is a bit too much of a blunt instrument and should not be included in a more complete game.

That said, I think there is definitely potential for playing with some of the more evocative parts of the fragmented parts of the text.

The oft-quoted fragment of one of the works Sappho springs to mind:

μνάσεσθαί τινά φαῖμι
καὶ ἕτερον
ἀμμέων.

someone will remember us
I say
even in another time.

Sappho

Within a section of the text that made it into the jam game is the sudden implicit violence of mention of various weapons, axes smeared with what is not said, followed simply by the word alone. I placed a long, blank pause before and after “alone” for effect.

…Suddenly the swords…,
and after the sheaths …,
the axes were smeared…
dagger and sword…
alone …
The Epic of Gilgamesh, tablet 5.

A segment shortly after features has some broken dialogue mentioning something in Humbaba’s belly, a throat and next, and Gilgamesh then saying “Humbaba’s face keeps changing!” which is begging for a scene involving the level’s tileset suddenly being replaced with disjointed meat level sprites as the boss becomes a horrible jumbled mess.

When you were still young I saw you but did not go over to you;
… you,… in my belly.
…,you have brought Gilgamesh into my presence,
… you stand.., an enemy, a stranger.
… Gilgamesh, throat and neck,
I would feed your flesh to the screeching vulture, the eagle, and
the vulture!"
Gilgamesh spoke to Enkidu, saying: "My Friend, Humbaba’s face keeps changing!

The Epic of Gilgamesh, tablet 5.

For what I actually managed to accomplish in the jam the only tricks I managed are the corrupted text and a short corridor level which becomes more visually broken as it goes along, but is completely static.

I made a pretty minimalist tileset for the background of six tiles with only two colours and tried my best to use them to give the impression of a forest, as per the epic narration.

I spent a while drawing these and then getting down trying to draw trees with them, though some of what I mapped out for the background ended up getting hidden by the tablet with the scrolling text, whoops.

As you cross the bridge you encounter a group tile in place of a bridge tile and above it a tree drawn in the same style as the first few background trees, but with the left and right side tiles swapped. Then and broken skull and a serpent implying some sort of non-functional boss mark the boundary for things really going wrong.

I still tried to keep to drawing similar tree shapes but with tiles swapped out to tiles from other parts of the spritesheet, including ones that only appear here, implying that some more game exists beyond what is implemented. Then the bridge itself corrupts and is replaced by corner ground tiles and then invisible but solid tiles as you walk into a screen of just skulls marking a little ending point.

I have expressed here some ideas for a larger game but I do not really have any plans to expand this out. It very much the kind of thing I might do eventually in a world where I had endless free time to work on every project idea I have, which is sadly not the world I live in, and it is far down the list and I only have very vague notions of how to expand this out into something bigger. It would probably not be done in Pico-8 as Pico-8’s size constraints and limited character count, not to mention tiny resolution, don’t make it ideal for games involving lots of text or expansive levels.



Táibléad Ⅴ

Triail Pico-8 a rinne me don Cork Game Jam. Is é “myth” an téama.

Is féidir an leaṫanaċ seo a léaṁ ċun tuilleaḋ a ḟáil.

Control with , and

Creidiúintí


Caoimhe
k=2^13::s::for a=0,k do
n=0 for x=0,8 do
n+=peek(k*3+a+x/3+x%3*64-65)end
poke(a,n==12 and 4 or n==16 and peek(a))end
memcpy(k*3,0,k)goto s

That is the entire source code for my my Pico-8 implementation of Conway’s Game of Life, which you can run here:

Control with , and

I made this as a tweetcart back when tweets were still 140 characters and I am still pretty proud of it. Let’s run through how this works!

If you have never heard of it, the Game of Life is a type of cellular automation, a simulation consisting of a grid of cells. Each cell is either alive or dead and with each iteration of the simulation the state of each cell changes based on the following rules, as copied from Wikipedia:

  • Any live cell with fewer than two live neighbours dies, as if by underpopulation.
  • Any live cell with two or three live neighbours lives on to the next generation.
  • Any live cell with more than three live neighbours dies, as if by overpopulation.
  • Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

It’s pretty hard to see how those rules translate to the above code, so I’ll try to explain it as best I can. It relies on some tricks specific to Pico-8.

The first thing in the code is is setting k=2^13, that is 8,192. This is a magic number that is going to have a few uses.

Then we set a label ::s::. This is a label we can use goto later on in the code to return to.

Then we start a for loop, for a=0,k do, counting from 0 to 8,192. This is the length, in bytes, of the part of the the Pico-8 virtual machine’s memory that holds the current screen state. Pico-8 has a resolution of 128×128 pixels, for 16,384 pixels total, and each pixel can have one of 16 colours. That means that the colour of each pixel can be stored in 4 bits—half a byte—and therefore the full screen information can be stored in 8,192 bytes. We are going to treat every byte as a single cell, which means every cell is actually made of two pixels. You can see how every cell in the simulation is one brown and one black pixel side-by-side.

The reason we’re doing this is so that we can iterate over the current screen state in order to determine the next iteration and which cells survive or die. By examining the screen memory directly we don’t have to create a different data structure for storing the cell information; it’s just whatever’s currently on screen. This saves an awful lot of characters.

Then, inside the loop, we start by setting n=0, this is going to be used to track the number of neighbours that every cell has.

Then we start up a new loop, for x=0,8 do, to iterate over all the neighbouring cells.

Which brings us to the first complicated expression, n+=peek(k*3+a+x/3+x%3*64-65). This is adding up the values of all the neighbours (for the purposes of this implementation, each cell is considered to be be one of its own neighbours). It peeks at the memory addresses of each of the neighbours, then adds it to the running total, stored in n.

k*3 (24,576 or 0x6000) is the start of the screen memory, the starting point for iterating over the screen data. Adding a to it is iterating over each cell in sequence in the memory.

Every byte (cell) is going to have a value of 0, for dead, or 4, for alive. I’ll explain why I used the value of 4 rather than the more obvious value of 1 later.

The screen memory is arranged in the order you would probably expect, it starts in the top left corner and scans left to right, top to bottom. The first 64 bytes are the first line of the screen, the next 64 bytes are the second line, etc. As such getting the cells to the left and right of the left and right of the current one is just a matter of taking away or adding one to the address we’re querying. Getting the cells above and below means subtracting or adding 64, respectively.

To get all nine neighbours (including the current cell itself) we need to check nine memory addresses: The current address, k*3+a, and offsets of -1, +1, -64, +64, -65, -63, +63, +65. This is accomplished with the +x/3+x%3*64-65 part of the expression as it iterates from 0 to 8. +x/3 will go from +0, +1, +2 over the course of the loop1. +x%3*64 cycles through +0, +64 and +128. Then the -65 corrects these to be centred around 0 (-1 for the horizontal and -64 for the vertical).

You may notice that this is going to behave weirdly at screen edges: For the first and last row it will be checking for “neighbours” in memory before and after the screen data. These are simply going to be blank as they aren’t otherwise being used for this programme. Additionally, due to the layout of the memory the left and right edges will wrap around and be treated as neighbours of each other, with a one pixel vertical offset. This weird behaviour is going to be the price we have to pay for trying to fit a mathematical simulation into a tweet2.

Once we have the total value of n totted up it’s time to write the next iteration of the simulation: poke(a,n==12 and 4 or n==16 and peek(a)).

Poke is the opposite of peak, it lets us write to a value in memory, and we’re going to just starting writing at address 0x0, which in Pico-8 is normally spritesheet data, but we’re not using sprites in this programme so we can treat it as effectively free memory.

The poke expression is a bit weird but effectively we’re either going to poke a value of 4, 0 or the current value of the cell (peek(a)).

Let’s go back to our bullet points from Wikipedia for a second. We need to rewrite them slightly because we’ve changed the way we counted living neighbours to include the cell itself as its own neighbour. Rephrasing it in those terms we have:

  • A live cell with fewer than three live neighbours dies.
  • A live cell with three or four neighbours lives.
  • A live cell with more than four neighbours dies.
  • A dead cell with exactly three live neighbours lives.

Or, simplifying it:

  • Any cell with three live neighbours is alive in the next iteration.
  • Any cell with four live neighbours keeps its current value in the next iteration.
  • Any other cell is dead in the next iteration.

Or, n==12 and 4 or n==16 and peek(a). If n==12 this evaluates as 4, the value we’re using for a living cell. If n==16 this evaluates as peek(a), write whatever the value for the cell is currently. Otherwise this evaluates as nil, and fortunately for us Pico-8 treats poke(a,nil) as being equivalent to poke(a,0), meaning every other case produces a dead cell.

Now we’ve iterated across the entire screen and made the next iteration of our simulation, the only thing left to do is copy the new iteration into the screen memory (memcpy(k*3,0,k)) and then start our loop again (goto s).

That’s it! Except, you might wonder, what about our starting state? We didn’t set any initial data, so why is there anything here in the first place when you run it? Well, our initial data is whatever is on screen when we run the code. You can have any starting state you want simply by having something different drawn to the screen when you hit run.

And that’s also why I used 4 for the value of a living cell: it produced interesting results when running directly after Pico-8’s boot screen rather than dying instantly, which happens if you used 13. 4 was chosen by trial and error. It’s also a bit easier to look at than using 1, which uses a dark blue colour rather than brown that’s harder to see against the black.

You can play around with this code yourself using Pico-8 Education Edition4 or check out my other Pico-8 projects

And that’s (actually) it! I hope you found this interesting.

  1. peek thankfully ignores any fractional values, so we can act as if these are being rounded. 

  2. At least to fit into what the size a tweet was back in the good old days, when men were men and tweets were tweets. Now I’m a woman and I’ve deleted my Twitter account… Actually, those might have been the bad old days. 

  3. Which would have shaved off two two more characters as the poke command would have been changed to n==3 and 1 or n==4 and peek(a)

  4. Click the button to start it and then hit Esc twice to open the editor. To run it again hit Esc again to bring up the command line, enter run and hit Enter


Caoimhe

This post uses obscure Unicode codepoints and custom fonts which may not display in RSS readers and some browsers.

A few years ago I made a Gaelic-style monospaced pixel font that I called Cló Piocó-8. This was originally just testing out the custom font mode in Pico-8 for fun. I then ended up making a truetype font using Pixel Forge.

If custom fonts can display it looks like this.

This was mainly for fun and I haven’t used it terribly much.

Around the same time I made it I also made a similar pixel font for Ogham. I think the reason for making these separately was because the main font was monospaced but the Ogham one wasn’t? Or perhaps it just didn’t occur to me to include the Ogham section with the original font at the time. Either way I’ve decided I wasn’t happy with them being two separate fonts so I made a new version of Cló Piocó-8 that includes the Ogham block.

I also changed another character: R.

The original R character in the font was more straightforwardly based on an Insular R and looked like this: R.

You might be wondering what an Insular R is.

Insular? Why is this R so withdrawn?

Because in the middle ages Ireland was a pretty isolated place, and Irish monks were left to their devices, eventually developing a style of writing called Insular script.

A Latin manuscript written in the Insular script.
7th century manuscript featuring Insular script via Wikimedia Commons.

When printing came to Ireland, which took a while, most things were printed in English. Gaeilgeoirí didn’t have much to read (but most of them couldn’t, anyway). The first book printed with an Irish type was Aibidil Gaoidheilge agus Caiticiosma in 1571, using a font which had been commissioned by Elizabeth Tudor, though it was actually a bit of a hodgepodge of Gaelic, Roman and Italic, with the new Gaelic letters resembling the Anglo-Saxon type made by John Day.

Since then Irish has been printed in both Roman and Gaelic type, the former often simply due to practical considerations of the availability or expense of Gaelic fonts or because it was seen as more modern. It is rare to see Gaelic script used now except for in decorative text such as signs and plaques.

«Saoirse don Phalaistín» painted on the side of a small building.
“Freedom for Palestine” painted on a building in Irish Carraroe via Gaelchló.

But I quite like the Gaelic-style scripts and—as evidenced by my homepage—I quite like playing with typefaces. I use Mínċló from Gaelċló for most the Gaelic script on this site.

But I will admit there can be some drawbacks to readability. Particularly with f, s and r, or rather their Insular variants, which Unicode has unique codepoints for: ꝼ ꞅ and ꞃ, respectively.

ꝼ ꞅ ꞃ

Compared to a Roman f, the Insular ꝼ almost appears as if it has been hammered into the ground like a post. The tail of the character dips below the line and the stroke is level with it, the top of the character only reaching to the same height as a small letter like e. But it is still distinct and recognisable as an f.

The problem starts with s. You might be familiar with a long s, which is basically an old-fashioned way of writing an s where it looks like an f without the stroke in the middle. The Insular ꞅ similarly strongly resembles an Insular ꝼ and if one is more familiar with Roman type it is very easy to confuse them at a glance. Many modern Gaelic typefaces simply use a Roman-style s instead for clarity, or offer the use of both using stylistic sets. I opted to use a Roman-style s when making Cló Piocó-8 for clarity. When your characters are only four characters high you need to be careful about legibility and it’s very common to do this anyway with Gaelic typefaces for both s and r.

But I still, in that first version, decided to go with an Insular ꞃ, a character that resembles a cross between the Insular ꞅ and an n, or perhaps a Greek η with the tail on the other side. In an attempt to make it not look too much like an n I cut one pixel off the right-side, to try and maybe make it look a bit more like a Roman r, but really it just makes it look weird. I left it like that for a long time, but I was never fully satisfied with it.

Deciding to change it

When I was making my custom cartridge designs for my Pico-8 projects (something else I could write a bog post on, really) I decided to use Cló Piocó-8 to sign my name and the URL of this site on them. This made me have to face that bloody R again. I was never happy with the compromise I made originally and quite frankly people were not going read it as an r. I don’t want anyone typing “oakneef.ie” into their browsers and finding nothing there.

My custom Pico-8 cartridge containing the Cló Piocó-8 font.
Check out my other Pico-8 stuff.

It was here that I came up with my new compromise: R. It is mostly an upper-case Roman R but with a little bit of a tail sticking down for a bit of Insular influence. I have actually started scribbling my r like this when handwriting in Irish as well.

Handwriting in a notebook of the standard insular f, s and r and my compromise r.

It took me a while to actually bring this change back to the font file itself but when making the 88×31 pixel badge for this site I was reusing elements from my Pico-8 cartridge design and it reminded me to go back and make the change, and I while doing it I also rolled the Ogham font into it as well, which I had also been intending to do for a while.

So check out Cló Piocó-8.

Appendix: Comparison of fonts

Source Serif 4 Mínchló Insular-style Mínchló Roman-style Cló Piocó-8 v1 Cló Piocó-8 v2
fsrn fsrn fsrn fsrn fsrn

Source for historical claims: The Irish Character in Print: 1571-1923, E.W. Lynam






Pico-8 animation editor

A Pico-8 animator editor I made for a project that never really got off the ground.

In particular it’s designed to help compress animations that have lots of repeated elements. E.g. In the example data in this cart the head layer is used across almost every animation, but only appears once in the exported spritesheet.

To this end it is very much optimised to favour saving space in the sprite sheet, and not optimised for CPU or RAM usage.

The version usable in browser here has some animations pre-loaded and you can play around, but you won’t be able to export any of them from this page. To do that you’ll have to download the cart and run it in your own copy of Pico-8.

Exporting

The editor defines characters, which have a set of animations, which have a number of frames, which each have a duration and ten layers to draw on. General usage is just to create animations, which can be exported via the “export” button. This will create four files:

  • spritesheet.png - the exported sprite sheet to be used in your game
  • metadata.p8l - lua table structure containing all the animation information needed to draw animations from the above spritesheet
  • metasheet.png - the same information, but stored in a different format as image data so that the animation editor is able to re-import it
  • debug.p8l - the exact data as in metasheet.png but in text format, just for debugging purposes

On startup the editor will import any data from metasheet.png and spritesheet.png back in so that you can continue editing where you left off.

Controls

  • The window on the left is for drawing, the ten windows on the right are ten layers each frame can use.
  • You can’t rearrange or add more layers but the C and V keys can be used to copy and paste the selected layer.
  • You need to create at least one character, animation and frame and select a layer before you start editing.
  • When entering names only English alphabet characters are accepted. Use enter to submit and / or \ to cancel. Backspace works as you would expect.
  • Use the arrows keys to move layers around (no wrapping - going off the edge will just erase data).
  • Use the WASD keys to move the origin point.
  • Use - and + to navigate through characters quickly.
  • Use [ and ] to navigate through animations quickly.
  • Use ’ and \ to navigate through frames quickly.
  • P/F toggles the paint or fill tool. Be warned there’s no undo button so be very careful with the fill tool.
  • ‘oni’ toggles onion skinning.
  • The ‘w’ next to it toggles wrapping for the onion skinning. When enabled and viewing the first frame in an animation, the onion skin layer will show the last frame from that animation.
  • ‘orig’ toggles showing the origin point for the current frame.

Importing

When you have your animations finished you should import the spritesheet into your own cart and copy the contents of metadata.p8l into an initialisation function in your game. You will then obviously need some special draw functions to do something with that data. Here is an implementation I have done as an example. You can download the Pico-8 cart for it here.