When the Game Boy was released back in 1989, using multiple megabytes of memory was inefficient from a design point-of-view because the cost of using so much memory was highly impractical for most companies to make back the initial production costs. However, as the years went by — and given Moore’s Law — the costs came down and, when it was discontinued in 2003, eight megabyte or larger cartridges were common.
However, by its original design, the Game Boy can only access 16 KB of ROM memory at a time. To get around this limitation, ROM sections of 16 KB code can be accessed through a technique called ‘banking’: one section of 16 KB code swapped for another.
By default, a Game Boy game, with no additional code or cartridge changes, is 32 KB with two 16 KB sections for all of its code, including any maps or large arrays.
Part of the way GBDK was designed was such that it doesn’t understand banking directly. Instead, it has the SWITCH_ROM_MBC1() function that can swap out existing ROM banks. However, to use additional banks requires additional compiling code instructions.
For each additional bank, the instructions “-Wf-boX -Wf-baX” need to be added where X is the bank a file represents.
To combine all the resulting files, use “-Wl-ytX -Wl-yoY -Wl-yaY” where X is the type of cartridge and Y is the number of total banks to the next power of two.
Note: If you are defining banks explicitly starting with at least one, use four total banks.
Switching, extern, and calling functions
Once a bank has been switched, its functions cannot normally be accessed. Anything that happens in that 16 KB is limited to that bank. However, using the keyword “extern,” a reference can be maintained into a separate bank when declaring a function. To use another bank’s functions, it is as easy as using something, like in the above example: extern void update().
Using this technique opens up the ability to build on the first concept from Part 4, as well: Make your code as module as possible.
Because of the much larger amount of memory now available through banking, the storage of more maps, arrays, and other larger data structures can be separated into other banks, initially loaded through SWITCH_ROM_MBC1() calls and then referencing them through use of extern. In fact, this is a common and even recommended practice to logically break up sections of dialogue, when using tile-based displaying, or to have many in-game area maps in different sections and as part of different ROM banks.
Before doing collision code, we should update our background tiles to something more useful than simply the alphabet. In the above file, I have used some tiles I developed for another project and included the original numbers and letters from the earlier parts of this series. Using these — and with a first, 0, blank tile — we can start to make areas that resemble other Game Boy games.
GBDK comes with no built-in physics or collision functionality. If we want collision code, we have to add it in as an additional function. For this example, we will use simple rectangle-to-rectangle checking. If one rectangle (from a starting position x, y and extending outward some amount) is overlapping with another rectangle (from another point some x and y amounts out), then the two are colliding.
We also need something to collide with, so another sprite is introduced and its position saved.
With our new colliding code, sprite0, when it overlaps with sprite1, switches its tile.
As becomes obvious from Part 3, the need for a smooth “Save, Export, Re-Compile” workflow is very important when using GBTD and GBMB with other tools. I highly suggest getting into the habit of saving constantly and making sure, with the maps and tiles, all files are as up-to-date as possible before compiling again as well.
However, as the compiling to test code can take time, I suggest the following:
Make your code as module as possible
Without objects and using only functions can make testing and debugging much more time-consuming, but separating the code into logical “chunks” can save considerable time when trying to move from one section to another. Planning ahead and having in mind, for example, a change from a menu to a level, can help separate functions into sections that can be tested as a group.
When possible, re-use variables
While not as important in smaller projects, having simple variables around like “i” and “j” can be very helpful for looping without need to create a new variable. Simply re-use the existing ones to run the loop and then re-use them again in another loop, later. This can save space in both the RAM and the ROM as a result.
Arrays are your best friend
While arrays are already the go-to for data structures in C, and because ROM space is an issue, having an allocated set of positions to store things like a player’s coordinates can save space and makes more logical sense to group them at the same time. This can also be written about “enemies” (or whatever, other obstacles might be on the screen). Adjusting multiple array locations and then using them to display things like meta-sprites are a required technique.
Use the 20 sprite limit wisely
GBDK can only update 20 sprites at a time. Depending on the project, this could be safely ignored or become a vital part of moving tiles around. Keeping an external map either as part of the comments or in anther file can help save your sanity when swapping tiles around and then moving sprites after.
As discussed in both Part 1 and used in Part 2, the Game Boy has a limited amount of graphical storage. You can only have 256 tiles of 8×8 pixels. This limits what you can do and, more importantly, dictates how you compose tiles on the screen as a result.
However, as glossed over in Part 2 and now explained in Part 3, you can generate the tiles and maps themselves using two sets of tools GBTD and GBMB.
Game Boy Tile Designer
Found here, the Game Boy Tile Designer will be your very best friend when it comes to create and exporting tiles. Beyond simply allowing you to design — hence the word in the title — tiles, it also allows you to copy them from one slot to another and, most importantly, uses functionality called “Split Paste” to paste content from another image program into 8×8 tiles.
For example, for Part 2, I used the following set of tiles I developed in another program. From there, I selected the whole image and copied it into the Windows clipboard.
In GBTD, go to Edit -> Split Paste.
Now, all of the tiles have been arranged as an increasing set starting from what position was selected from the right-hand side. (In this case, the first, 0, position.)
Once that is done, it is a matter of “including” them in a Game Boy program. To do that, go to File -> Export To.
On the next screen, click on the drop-down menu and choose the “GBDK C file (*.c)” option.
Select “Browse” to find the location and give the file a name. As well, change the label to something useful and finally, as a last step, set the number of tiles to export in total in the “From” field. (In this example, it is 47 tiles.)
Once exported, the “alpha” tile set will look much like the “alpha.c” file from Part 2.
Note: The above, pasting and exporting, were the exact steps I performed to generate the files for Part 2.
Once exported, be sure to File -> Save the set as “alpha.gbr”. (The result will be used in the next step and will allow you, when re-opening the file, to use File-> Export in the future, or simply Ctrl-E as a shortcut to update the file.)
GBTD and GBMB are created to feed into one another. The files saved from GBTD can be opened by GBMB to use the tile to create larger ‘maps’ of areas or as part of the creation of a meta-sprite, a sprite made up of multiple tiles.
In our example, go to File -> Map Properties and select the file created in GBTD, “alpha.gbr”
When asked for width and height, use 10×2.
In GBMB, the left-click is used to select a tile from the right-hand list of perform an action from the left-hand listing. Right-clicking places a tile on the map.
Continuing from the discussion from Part 2, we can use the fact that tile 48 is ‘blank’ to use it as a way to make the map ‘blank’ to start.
Then, using one letter at a time, we can write “HELLO WORLD” on the map.
Once we have the map arranged as we like, we can export the map like in GBTD through the File -> “Export to…” option.
Also like in GBTD, select the “GBDK C file (*.c)” option, use “Browse” to set a location and name, and set a label.
Unlike in GBTD, click on the “Location format” tab and set “1 plane (8 bits)” and, in the properties, select “Tile number” from the drop-down menu. Once done, click the “OK” button.
The resulting file, much as “alpha.c” using GBTD was “alpha.c” from Part 2, “helloWorld.c” will be the same except for the addition of the header comment information.
Once exported, be sure to File -> Save the map. This will save you time in re-creating it and, like with GBTD, will remember the location you saved the file and allow for quick File -> Export or Cntl-E exporting.
Unlike Part 1 or Part 2, there are no code changes to “main.c” in this Part. However, it is included here for reference.
Note: The creation of “blankScreen.c” and “sprites.c” are not shown in this post. However, given the techniques explained, their creation, as a 20×18 map of tile 48 and sprites drawn as tiles, is fairly self-explanatory.
In Part 4, I will cover the basics of colliding sprites and project management.
As was covered in Part 1, the Game Boy uses two main sections of graphical memory: sprites and background. In order to place a tile for the background, it must be in the background. In order to place a tile for a sprite, it must be in the sprite memory. (There are ways to read and write directly to the different memory locations using GBDK functions and effectively swap things, but that’s a much more advanced topic.)
For our example of using background tiles, we will be printing the classic words “Hello world.” However, to do that, we need tiles to actually write.
Download or copy the content of “alpha.c” into a file named exactly that: alpha.c.
Note: As was mentioned in Part 1, tiles are represented as collections of hexadecimal numbers. The array alpha is 47 tiles representing numbers 0 – 9, 26 capital letters, and some additional punctuation.
Next, in order to display these tiles, we will change the “main.c” from Part 1 to load these tiles and then display a pattern of them.
Running the build script will produce the following response when run in an emulator.
While not particularly useful as a first demonstration, it shows two things:
Unless changed, the background remains whatever was last written to it
The Game Boy hardware makes assumptions. In this case, when reset, it makes its background tile memory to be all zeros. Without other instructions, it took the first tile, a ‘0’, and repeated it across the entire screen.
To print “Hello world” we need one additional thing: an array of tile locations.
In programming Game Boy games, it is often much more convenient to produce a ‘map’ of where you want tiles to go and then use this map instead of arranging tiles one at a time. In fact, GBDK’s API is built with this in mind. Using an additional function set_bkg_tiles, we can write out a section of tiles at a time. However, before we can call it, we need that map.
Like with “alpha.c”, copy or download “helloWorld.c” and add it to the folder containing the other files.
To use the map, we need to update “main.c”.
After building the new files, we get a different response:
Note: Within the helloWorld array, I used “0x30” as a blank. This is tile position 48. Yet, remember, only 47 tiles were loaded. The 48th tile position, like with the other hardware assumption of showing all zeros, is because the background is reset, too. Without loading a new tile in that position, it will remain blank.
Finally, before getting to input and moving sprites around on the screen, we will do one more thing: create an additional blank map. As explained in the above note, the 48th position in the background table is blank. So, in order to create a blank screen, we can use this as we did with the helloWorld array. We simply create a new map of 20 tiles by 18 tiles (or 160 pixels by 144 pixels).
And, finally, adjusting our “main.c” to use this additional map, and to sneak in some user input, here’s the updated version.
Now, when we press ‘B’, we write a new map of ‘blank’ tiles over the old output, effectively creating a blank screen.
Note: It is far more efficient to set the first tile of the background table to be ‘blank.’ That way, by default, the screen will show either all dark or white, depending on your needs. However, for the sake of the above examples, it is worth showing how using the assumptions of the hardware against itself can save time and later effort.
Sprites work much like background tiles. They are loaded and used with functionality that works the same way internally. However, like with background tiles, we need some sprite tiles to work with before we can begin to move them around in any manner.
With the introduction of an additional file to include, we need to change “main.c” once again. We also need to introduce some new functions in order to use the sprites.
The function set_sprite_data works like set_bkg_data to load some array of values into sprite memory. set_sprite_tile assigns the first movable sprite to be some tile from the sprite tile set. In the above case, it uses the first tile in the sprite tile set.
Note: There is a hard limit to the number of moving sprites at a time set at 20 (0 – 19) with only 10 sprites moving per line. GBDK stores addresses for these moving sprites, which can be accessed through the set_sprite_tile function. To move larger sets of tiles at a time, especially in the case of larger visual sprites, multiple calls to set_sprite_tile are needed.
While our current code loads and prepares sprites for movement, it does not do anything quite yet. To move a sprite, we need the move_sprite function.
Now, after adding in some additional checks for user input and using the move_sprite function, we can move a sprite around on the screen using the directional input.
Note: The below GIF demonstrates one of my favorite aspects of the Game Boy: screen wrap. Without some type of checks in place, a sprite can move all the way ‘right’ and end up back on the edge of the left side.
With loading background and sprite tiles and then moving them around, we can make most of the games which came out for the original Game Boy. It may not seem that way, of course, but most of the ‘work’ in programming Game Boy games comes not in the coding itself, per se, but in memory and screen management. As with the hardware assumptions mentioned in this post, taking advantage of what the Game Boy assumes and making smart decisions about how to load things can speed up a project considerably.
In Part 3, I will cover two useful tools for helping with Game Boy programming projects: Game Boy Tile Designer (GBTD) and Game Boy Map Builder (GBMB).
While the Game Boy have been discontinued since 2003, the system itself, its underlining chip and instruction set, remain a viable way to explore video game programming for smaller, more constrained hardware. Luckily, instead of writing in assembly code for the device as many programmers did at the time, we can now write in a modified version of the C programming language to create games using a library called GBDK, the Game Boy Developers Kit!
Note: For this series, and starting with this first part, I’m going to assume a Windows environment. GBDK can, in fact, be compiled on different platforms, but many of the additional tools for easier map and tile creation run on Windows.
Once downloaded, unzip the files to your hard drive, preferably in a location like “C:\gbdk”.
Note: Because later build scripts will use “C:\gbdk\bin” as part of their instructions, it is highly recommended to placed the files on the C drive or another easily accessible location.
As mentioned before, GBDK uses the C programming language. For those coming from something like C#, Java, or other high-level languages, it will look very familiar. However, it also comes with a few new general “rules” to follow for the most efficient code for the platform.
Objects, as they might exist in other languages, aren’t in C. And you can’t use structs to mirror this functionality, either. Most of your code will be based on functions and arrays.
Whenever possible, use globals, too. Instead of defining a variable within a function, define it once and then, if possible after, re-use that same name as a way to cut down on calls to the stack.
Instead of using “int”, use “UINT8” at all times.
Other than in a few specific cases, most values will be in hexadecimal.
Game Boy Hardware
Summed up in four words, the hardware for the Game Boy can be stated as this: you have 256 tiles. That’s it. You can’t add more to the system, and each tile is 8 pixels by 8 pixels. This means, in practice, that you must make choices about what graphics will be included, where they will be shown, and how often you can repeat something in advance. Decisions about content, unlike for a more modern platform, means that, as a developer, you must be conscious of how much space is being devoted to things like a menu when you might also want to include an extra level. The constraints of the hardware make balancing space concerns an important part of the design of any Game Boy game.
The Game Boy provides two main memory sections of graphics in its hardware: sprites and background. As part of background, it also has a ‘window’ that can be used in different ways. However, unless you want to layer things, the window and background shared space can be thought of as simply the ‘background’ by itself. A tile (8×8 pixels) is either one or the other as well. It can either be loaded as part of the sprites or it can be part of the background. And, in total, sprites cannot exceed 128 (0 – 127) without running into the background table space.
Once loaded, and in general, tiles are referenced by their location within the table and can moved (sprites) or placed (background). Tiles are also defined by a series of hexadecimal values representing which color to show.
For example, for a blank, 8×8 tile, the string of values would be the following:
Like other platforms of its type, the Game Boy must be told, specifically, when to do things like turn on, show sprites, or increase the volume. For the most part, these can be thought of as ‘switches’: you turn them on or off depending on your needs.
Before we can compile a program, we need a minimum of two files: the build script and C source.
Save both of the above files. If GBDK has been installed correctly (or its path changed in the build script), the file should compile and produce a “main.gb” file to be run on your Game Boy emulator of choice. Congratulations! You have successfully compiled a Game Boy game and are ready to move on to Part 2: Placing Tiles and Moving Sprites!
For this project, after trying several image-editing libraries, I settled on JIMP for both the editing and retrieval processes. (If you want to break them up, I recommend Request as a good library that supplies wrappers around any basic network functionality you’d need.) For access to Flickr, I used flickr-sdk.
Note: While Flickr points you to flickrapi for a Node.js module for Flickr API access, I DO NOT recommend it for projects on remote servers or services like Heroku. It will create multiple folders and attempt to cache images, something far from ideal for quickly retrieving random images.
To get started, install the following modules in your working directory or globally, if you want access to them across projects.
npm install jimp
npm install flickr-sdk
npm install -g flickr-oauth-dance
After installing flickr-sdk, you will need an keys from Flickr to continue. For that, use “flickr-oauth-dance”.
Note: flickr-oauth-dance will read your Flickr credentials from your Chrome cookies. If you have not already, log into Flick using Chrome before the next step.
From the command-line run: flickr-oauth-dance
flickr-oauth-dance will ask for various information about your app including a name and a description. Before producing the access key needed, it will also ask you to confirm the permissions of the app. For testing purposes, I recommend “read” to start and then, later, changing it if you also want to upload or change images on Flickr.
Examine “local.json” for your API and access keys.
Copy and paste the above code, putting in the API and Access Tokens retrieved from flickr-oauth-dance earlier.
I was recently asked to help with a project in the Snowman story format. Having not spent much time in it since an earlier version of Twine, I had to brush up on the changes to how functions were called and what properties were available. During the couple hours while I was looking for a working solution to a problem, though, I noticed there wasn’t much in the way of documentation for the format. There are some notes here, of course, but not much in the way of a listing of functionality unless you look at the documentation in the code.
I’ve hoped to change that with a “cheatsheet” I’ve developed that has all of the properties of window.story and window.passage listed out with their types and descriptions directly from the source code itself. If you need a quick reference for a property or function, this should help.