once upon a time I heard of a technique called…
bitwise autotilingI learned about it back when I was building 2D Minecraft clones using Construct 2, and I wanted my terrain to look nice as it does in Terraria
now given a tileset, such as the one below that I drew a while ago, we can assign each tile to a set of cardinal directions. I’ll indicate where there’s a connection between individual tiles with the letters N, E, S, W, standing for the cardinal directions North, East, South, and West.
<ul class=”tileset-demo”> <li class=”full-image”> <img alt=”a 16-tile tileset of 8x8 pixel metal” src=”/static/pic/01HPHVDRV0F0251MD0A2EG66C4-tilemap-heavy-metal-16+pixel+width160.png”> </li> <li class=”tileset-pieces”> <span class=”metal x-0 y-0”><span class=”east”>E</span><span class=”south”>S</span></span> <span class=”metal x-1 y-0”><span class=”east”>E</span><span class=”south”>S</span><span class=”west”>W</span></span> <span class=”metal x-2 y-0”><span class=”south”>S</span><span class=”west”>W</span></span> <span class=”metal x-3 y-0”><span class=”south”>S</span></span> <span class=”metal x-0 y-1”><span class=”east”>E</span><span class=”south”>S</span><span class=”north”>N</span></span> <span class=”metal x-1 y-1”><span class=”east”>E</span><span class=”south”>S</span><span class=”west”>W</span><span class=”north”>N</span></span> <span class=”metal x-2 y-1”><span class=”south”>S</span><span class=”west”>W</span><span class=”north”>N</span></span> <span class=”metal x-3 y-1”><span class=”south”>S</span><span class=”north”>N</span></span> <span class=”metal x-0 y-2”><span class=”east”>E</span><span class=”north”>N</span></span> <span class=”metal x-1 y-2”><span class=”east”>E</span><span class=”west”>W</span><span class=”north”>N</span></span> <span class=”metal x-2 y-2”><span class=”west”>W</span><span class=”north”>N</span></span> <span class=”metal x-3 y-2”><span class=”north”>N</span></span> <span class=”metal x-0 y-3”><span class=”east”>E</span></span> <span class=”metal x-1 y-3”><span class=”east”>E</span><span class=”west”>W</span></span> <span class=”metal x-2 y-3”><span class=”west”>W</span></span> <span class=”metal x-3 y-3”></span> </li> </ul>
note that the state of connection for a given cardinal direction can be represented using two values: connected, and not connected. two values make one bit, so we can pack these four connection states into four bits, and use that as an array index!
for that to work though, we need to rearrange our tilemap somewhat such that we can index into it easily using our integer. assuming we pack our bits as
NWSE
(bit 0 is east, each next bit we go clockwise), therefore the final arrangement is this:<div class=”horizontal-tile-strip”> <span class=”metal x-3 y-3”></span> <span class=”metal x-0 y-3”><span class=”east”>E</span></span> <span class=”metal x-3 y-0”><span class=”south”>S</span></span> <span class=”metal x-0 y-0”><span class=”east”>E</span><span class=”south”>S</span></span> <span class=”metal x-2 y-3”><span class=”west”>W</span></span> <span class=”metal x-1 y-3”><span class=”east”>E</span><span class=”west”>W</span></span> <span class=”metal x-2 y-0”><span class=”south”>S</span><span class=”west”>W</span></span> <span class=”metal x-1 y-0”><span class=”east”>E</span><span class=”south”>S</span><span class=”west”>W</span></span> <span class=”metal x-3 y-2”><span class=”north”>N</span></span> <span class=”metal x-0 y-2”><span class=”east”>E</span><span class=”north”>N</span></span> <span class=”metal x-3 y-1”><span class=”south”>S</span><span class=”north”>N</span></span> <span class=”metal x-0 y-1”><span class=”east”>E</span><span class=”south”>S</span><span class=”north”>N</span></span> <span class=”metal x-2 y-2”><span class=”west”>W</span><span class=”north”>N</span></span> <span class=”metal x-1 y-2”><span class=”east”>E</span><span class=”west”>W</span><span class=”north”>N</span></span> <span class=”metal x-2 y-1”><span class=”south”>S</span><span class=”west”>W</span><span class=”north”>N</span></span> <span class=”metal x-1 y-1”><span class=”east”>E</span><span class=”south”>S</span><span class=”west”>W</span><span class=”north”>N</span></span> </div>
packing that into a single tilesheet, or rather tile strip, we get this image:
in JavaScript, drawing on a
<canvas>
using bitwise autotiling would look like this:javascript for (let y = 0; y < tilemap.height; ++y) { for (let x = 0; x < tilemap.width; ++x) { // Assume `tilemap.at` is a function which returns the type of tile // stored at coordinates (x, y). let tile = tilemap.at(x, y);
// We need to treat some tile as an empty (fully transparent) tile. // In our case that’ll be 0. if (tile != 0) { let tileset = tilesets[tile];
// Now it’s time to represent the tile connections as bits. // For each cardinal direction we produce a different bit value, or 0 if there is // no connection: let connectedWithEast = shouldConnect(tile, tilemap.at(x + 1, y)) ? 0b0001 : 0; let connectedWithSouth = shouldConnect(tile, tilemap.at(x, y + 1)) ? 0b0010 : 0; let connectedWithWest = shouldConnect(tile, tilemap.at(x - 1, y)) ? 0b0100 : 0; let connectedWithNorth = shouldConnect(tile, tilemap.at(x, y - 1)) ? 0b1000 : 0; // Then we OR them together into one integer. let tileIndex = connectedWithNorth | connectedWithWest | connectedWithSouth | connectedWithEast;
// With that, we can draw the correct tile. // Our strip is a single horizontal line, so we can assume let tilesetTileSize = tileset.height; let tilesetX = tileIndex * tilesetTileSize; let tilesetY = 0; ctx.drawImage( tilesets[tile], tilesetX, tilesetY, tilesetTileSize, tilesetTileSize, x * tileSize, y * tileSize, tileSize, tileSize, ); } } }
and that gives us this result:
<canvas is=”tairu-editor” data-tilemap-id=”bitwiseAutotiling” data-tile-size=”40” > Your browser does not support <canvas>. <img class=”resource” src=”/static/pic/01HPMMR6DGKYTPZ9CK0WQWKNX5-tilemap-heavy-metal-bitwise-16+pixel+width640.png” data-tairu-tileset=”1”> </canvas>
but if you play around with it (or have already played around with it, and are therefore left with a non-default tilemap)
…something seems awful about it doesn’t it?
something’s off about the corners. let me give you a fresh example to illustrate what I mean:
<canvas is=”tairu-editor” data-tilemap-id=”bitwiseAutotilingChapter2” data-tile-size=”40” > Your browser does not support <canvas>. <img class=”resource” src=”/static/pic/01HPMMR6DGKYTPZ9CK0WQWKNX5-tilemap-heavy-metal-bitwise-16+pixel+width640.png” data-tairu-tileset=”1”> </canvas>
bitwise autotiling is a really cool technique that I’ve used in plenty of games in the past
as I mentioned before, I’ve known it since my Construct 2 days, but when it comes to my released games [Planet Overgamma] would probably be the first to utilize it properly
TODO video of some Planet Overgamma gameplay showing the autotiling in action
this accursed game has been haunting me for years since; there have been many iterations. he autotiling source code of the one in the video can be found here.
but one day I found a really cool project called Tilekit