Ahh, Christmas time...which means free time! Mark got me this video game called “Life is Strange.” He said it reminded him a little bit of our lives. So I’ve been playing all day.
Earlier on Discord I was asked how I go about making sprites and tilesheets, so let’s go over my general practices.
What you’re seeing above is a very simple map setup. The map is simply a two dimensional array of boolean values. the sprites are dynamically chosen out of 16 possible variations for a connecting texture. There’s also lighting effects, but I’ll glaze over that for now and just say it’s magic.
Now before I begin on how this works, i’m going to have to define bit fields. A bit field is essentially a way to store multiple booleans as a number. So, let’s say we have a bit field for some color definitions. We’ll say, in three booleans, which color is enabled. red, green and blue.
000 = black = 0 100 = red = 1 010 = green = 2 001 = blue = 4
Now, using binary or, we can combine these colors for other values.
So we’ve got 8 possible colors here, and we’ve stored that information in 3 bits. Pretty neat, right? now how does this apply to tilesets? Well, like I said before, the tilesets I make are typically 16 tiles that are determined by connected tiles. So what I do in code is retrieve a tile’s bitfield of nearby tiles.
So take a look at this quick mock-up of that process. If we were to check that pink square for it’s bitfield, we’d check the top, left, right, and bottom tile. if they match the pink block, then we flip that corresponding bit.
1000 = 1 = top 0100 = 2 = left 0010 = 4 = right 0001 = 8 = bottom
I’ll spare you all the individual possibilities, but four bits will give us 16 options. and they go in a very particular order
Basically, starting with 0 (no connected tiles), we go through all the options until we hit 16 (all connected tiles). In this example, the tilesheet starts at index 32. So let’s grab a quick example. if we have a bit field that corresponds to the top, bottom, and right (1011) that means the integer value of that bit field is 1 + 4 + 8, 13. so we’ll do 32 + 13 to get the sprite index we need, 45.
Seems about right. of course this is just placeholder tiles. how about a real example? Let’s check out the tileset for picowars.
Here we have the tileset for water tiles. Now if you’re clever you’ll notice something strange. the corners are a always going to have the inner cliff. For example, let’s take a look at this example.
To compensate for this fact, you’re gonna need to do some trickery. You could expand your bit field to 8 bits to take into account for corners, but an 8 bit integer is 256 possibilities. Not entirely the best plan in PICO-8, as you’ve only got 256 tiles to begin with. Thankfully in this example, the only real change I would need to do for these tiles, is draw blue over the corners, so on rendering, I’ve got another check to do that, and save myself some tilespace.
Sometimes you get lucky though, and the only real change you need to do is on the 16th tile, Take a look at the first example in this post and you’ll see that the brick tiles inner corner piece, it’s a brick for sure, but it’s only rendered on those inner corners. the bit field on sides is 16, but will only render if the bitfield on corners doesn’t equal 16. That tileset still works in 16 tiles, and simply doesn’t render those tiles completely surrounded by blocks.
Anyway, hopefully this bit field shenanigans has taught someone out there something about making tilesets in PICO-8 or elsewhere. Maybe a bit about binary too. Let me know if you have any questions on my ask box and I’ll get to it!