Level Up Your Snake, Part 1: Drawing Graphics the Game Boy Way
- Marcel Pflug
- Jul 5
- 7 min read
In an earlier series we built a complete Snake game for the Game Boy in C and ran it on a real DMG-01. That game works, but it is bare: no title, no score, no lives, and a rather abrupt end. This new series levels it up, adding a title screen, a score, lives, a proper game-over screen, sound and a pause function, one feature per part. Before any of that, though, we need something the first game deliberately went without: graphics and text of our own. So we begin exactly where the Game Boy's own artists began, by drawing.
By the end of this part you will understand how graphics were made for the Game Boy, and you will have designed two things we use for the rest of the series: a small font, and a start-screen picture. No prior coding experience is needed; we will read every line together in plain English.
How the Artists Drew for the Game Boy
In 1989 there were no drag-and-drop art tools of the kind we know today. A Game Boy artist often began much like someone doing cross-stitch: on squared paper, one small 8 by 8 tile at a time, filling each of its 64 squares with one of just four shades. A logo, a character or a letter was then assembled from these little tiles like a mosaic, and finally turned into the numbers the console understood.
Trivia, since people always ask: did programmers really work out every pixel as a number by hand? In the very early days, and for lone hobbyists, yes, that graph-paper-to-hex conversion was a genuine rite of passage. Professional studios did not stay in that world for long, though. They worked on development computers with graphical tile editors, painting each 8 by 8 tile with a cursor while the tool wrote out the numbers automatically. Today nobody types hex by hand at all: you draw your tiles in a pixel-art program such as Aseprite, or a dedicated tool like Game Boy Tile Designer, or design whole games visually in GB Studio, and a converter (for example GBDK's png2asset) turns your picture straight into the data the console needs. We are doing it the old, manual way in this series purely because it makes the machine impossible to misunderstand.
Four Shades, Two Bits, Sixteen Bytes
Because every pixel is one of four shades, it can be described by two bits (a bit is just a single yes-or-no value in the computer's memory). Each row of eight pixels therefore needs two bytes, one for each bit, and a full tile of eight rows takes sixteen bytes. That is why, back in the beginner series, our tiles were always sixteen numbers long. Here is the food tile again, a diamond:
// the food tile: a diamond, 16 bytes (two per row)
0x00,0x00, 0x18,0x18, 0x3C,0x3C, 0x7E,0x7E,
0x7E,0x7E, 0x3C,0x3C, 0x18,0x18, 0x00,0x00If those numbers look intimidating, here is the trick to reading them. The tile is eight rows tall, and each row is described by a pair of numbers, so there are eight pairs. A line beginning with two slashes is just a comment, a note for humans that the console ignores. A value like 0x00 means an empty row with nothing lit; the 0x in front simply marks it as a hexadecimal number. In the very next section we will work out, step by step, exactly where such a number comes from.
Designing a Font
To show a score, or the word SNAKE, we need letters and numbers, and on the Game Boy a letter is simply another tile. We design a compact five-by-seven pixel letterform inside each eight-by-eight tile, leaving a little breathing space around it so the words do not run together. Draw the twenty-six capitals and the ten digits once, store them as tiles, and you can write anything on screen. This is our little museum font, the alphabet and numbers we will use for every screen from here on.

Designing One Letter, Pixel by Pixel
To see exactly how a tile is born, let us build one letter from scratch: a capital A. First we sketch it on the eight-by-eight grid, colouring in the squares that should be dark and leaving the rest light. Straight away the familiar shape appears, a narrow peak, two uprights and a bar across the middle, with an empty row at the very bottom so the letters below have room to breathe.

Reading the grid one row at a time, we turn each row into a single number. Here is that same A, row by row:
// the letter A, one row at a time
0x38, // ### the peak
0x44, // # # the uprights begin
0x44, // # #
0x7C, // ##### the bar across the middle
0x44, // # #
0x44, // # #
0x44, // # # the two legs
0x00 // a blank row for spacingRead the little comment beside each number and you can find the letter hiding in the digits: 0x38 is the narrow peak, each 0x44 is a row with only its two edges lit, 0x7C is the bar across the centre, and 0x00 is the empty row at the foot. But where do those particular numbers come from? That is the part worth slowing down for.
How Each Row's Number Is Worked Out
Here is the simple rule behind every one of those numbers. Think of the eight squares in a row as eight switches. Each square has a fixed value that depends only on its position, starting from the left: 128, 64, 32, 16, 8, 4, 2, 1, each one exactly half of the one before it. To turn a row into its number, you add up the values of only the squares that are switched on (the dark ones), and then write that total in hexadecimal.

Take the upright row of our A, the one written 0x44, which has just its two edge squares lit. Looking at their positions, those two squares are worth 64 and 4. Add them together: 64 + 4 = 68. The last step is to write 68 in hexadecimal, the base-sixteen counting that programmers use. Hexadecimal counts in sixteens, so 68 is four sixteens (that is 64) plus four more, which is written as 44, giving us 0x44. That is the whole calculation: pick the lit squares, add their position values, convert the total to hex.
The other rows work the very same way. The peak of the A lights the three middle squares, worth 32, 16 and 8; add them, 32 + 16 + 8 = 56, and 56 in hexadecimal is 0x38 (three sixteens is 48, plus eight, written 38). A completely empty row lights nothing, so it adds up to 0, written 0x00. And the bar across the middle lights five squares, 64 + 32 + 16 + 8 + 4 = 124, which is 0x7C. Work down all eight rows like this and you have built the letter by hand, one number at a time. A tile editor simply does this addition for you, but now you know exactly what it is doing under the hood.
One last detail we skipped earlier: in the real font file each of these values is written twice in a row, because the Game Boy stores two copies for its four possible shades. Our font uses only the darkest shade, so the two copies are identical, which is why the finished tiles read 0x38,0x38, 0x44,0x44 and so on.
Once the letters exist as tiles, writing a word is just placing the right tiles side by side. This little helper does exactly that:
// each character is just a tile; write a word by placing tiles
void draw_text(uint8_t col, uint8_t row, const char *s) {
while (*s) set_bkg_tile_xy(col++, row, tile_for(*s++));
}Even if you have never written a line of code, you can follow what this does. The word void just means this is a reusable instruction, which we have named draw_text, that we can call whenever we want to write something. It is handed three things inside the brackets: a column and a row where the text should start, and the text itself (called s). The line while (*s) means keep repeating the next step as long as there are still characters left in the text. That step, set_bkg_tile_xy(col++, row, tile_for(*s++)), quietly does three small jobs at once: tile_for finds which tile matches the current character, set_bkg_tile_xy places that tile at the current column and row, and the two ++ marks then nudge us one column to the right and one character further along the text. Round and round it goes until the text runs out, and the word has appeared on screen, letter by letter.
The full font, all twenty-six letters and ten digits already turned into tiles, lives in the downloadable project at the end of the series, so you never have to type it out by hand.
Drawing the Start Screen
With tiles and a font in hand, a title screen is simply careful arrangement. We place the word SNAKE near the top, coil a little snake underneath from the same body tile the game uses, drop a single piece of food beside it, and write PRESS START lower down. Notice that we are no longer thinking about individual pixels at all; we are arranging ready-made tiles on the twenty-by-eighteen grid, which is exactly how Nintendo's own title screens were built. The result already looks like a real game waiting to be played.

Coming Up in Part 2
A picture on its own is not a title screen yet. In Part 2 we make it interactive: the game will show this start screen the moment it boots, sit patiently on it, and wait for the player to press START before the snake ever appears. That single change is what turns a program into something that feels like a cartridge.
New to all this? Start with the beginner series, Build Your Own Game Boy Game, which builds the Snake we are about to improve. And to see the machine we are drawing for, browse the collection.








Comments