This is a small project to show how does the gameboy development works to my team.
https://www.gbdkjs.com/docs/installation/
Really complete blog where you can find a much more detailed explanation over key-concepts in GameBoy Programming: https://blog.flozz.fr/2018/10/01/developpement-gameboy-1-hello-world/
/!\ All the images are coming from this blog you should really take a look at this link !
Some key-numbers to begin with:
- released in 1990
- 8 ko of RAM,
- 8 ko of video memory,
- only 4 greyscales with a resolution of 160×144 pixels.
A game usually has between 32 ko and 4 Mo of ROM.
- UINT8 waitpad(UINT8 mask): blocking execution to wait for key corresponding to the mask to be clicked.
- void waitpadup(void): blocking execusion to wait for user to release all gamepad buttons. It's particularly convenient when the user as to click
- joypad:
And a mask for each button:
- J_UP,
- J_DOWN,
- J_LEFT,
- J_RIGHT,
- J_A,
- J_B,
- J_START,
- J_SELECT
Be aware that you will code on a 8-bit machine. For that reason an integer should only be 8-bit long. To do so, some recommended types are available like INT8 and UINT8.
The Gameboy screen's resolution consists of 160 * 144 pixels, but not addressable. To edit one pixel, one must uses tiles. A tile is a square of pixel (8 * 8) that covers the screen. They can be considered as Lego to build our screen. That way we can reuse them to save some memory. There is three different types of images used in Gameboy Programming:
- background: 32 * 32 tiles (bigger than the screen but used to enable scrolling)
- window: matching what you see on the screen in size (ie only of fraction of background)
- sprites: 1 or 2 tile-long objects (88 or 816) often used to represent characters or animated objects
The Gameboy's video memory is divided in three differents domains:
- tile data: to stock images used as tiles
- background map: to store the placement of our tiles in the screen. For instance, if we can to display the tile number 1 at the position (0; 0) we have to say it here.
- zone OAM (Object Attribute Memory): to stock all the information linked to each sprite (tiles, color, position...).
The memory domain corresponding to tile data is cut into three sub-domains:
/-----------------------------------\
Sprites (128 tiles)
/-----------------------------------\
Sprites OR Window/Background (127 tiles)
/-----------------------------------\
Window/Background (128 tiles)
/-----------------------------------\
We can therefore use a maximum of 255 tiles for a layer. If we use 255 tiles for the background and window, we will only dispose of 128 tiles for sprites.
Now that we have seen how memory is managed on Gameboy, you should ask yourself how does our console stores characters. We have previously used the "printf" method like it was given as a utility method but in fact, this has a great impact on our memory management... Look for yourself:
Now that we have seen how memory works it's time to create some tiles for our program. You can use any image editor you like to create them but you will need some specific converter to transform a png image into a c code like the one store in res/tilesets/background_window/cherry_wall.c
Then, you place it in memory (tile data):
set_bkg_data(0, 5, CHERRY_WALL);
The only thing left to do is to use the tile saved in memory and indicate their position on screen:
For that, we indicate the mapping stored in res/tilemaps/first_map.c that will be inserted into the background map zone in memory:
set_bkg_tiles(0, 0, 20, 18, FIRST_MAP);
- the first two parameters gives the coordinates where we would like to place our tilemap
- the following two parameters gives us the size of our tilemap
- the last parameter is simply a pointer to our data.
Lastly, we must show the background to the user since the background is hidden by default:
SHOW_BKG;
We quickly went over how to use our tileset. But what if I want to create mine ? How does it work ? Well, it's not that complicated, but it's not that easy as well.
First, we map our image colors' to a number corresponding to a shade of our pallet:
Then, we convert this number in binary:
And finally, we convert this number to hex using the following schema:
A library is available to automate this process: img2gb
A scrollable domain of 32 * 32 tiles.
There are two main methods useful when working with background.
The first one is:
void scroll_bkg(INT8 x, INT8 y);
using relative position
and the second one:
void move_bkg(UINT8 x, UINT8 y);
/!\ Warning: these coordinates are in pixels !
While the background and window layer are forced to use a grid, sprites can be positioned anywhere we like with pixel precision.
They can be 88 long or 816 long.
There are some restrictions while using sprites such as those:
- you cannot have more than 40 sprites at the screen at the same time and at most 10 on the same line.
- you only have 3 different shades to color your sprite as one color is transparent to show the background. All of these information are registered in memory as OAM (Object Attribute Memory).
While we were using
set_bkg_data(0, 5, CHERRY_WALL);
Now we will be using:
void set_sprite_data(UINT8 first_tile, UINT8 nb_tiles, unsigned char *data);
These methods are actually doing the same thing but at different places in memory.
As before, we can choose to display sprites or not with a simple switch:
SHOW_SPRITES;
HIDE_SPRITES;
Finally, to show a sprite, we use:
void set_sprite_tile(UINT8 nb, UINT8 tile);
where nb is between 0 and 39 and is the unique id of our sprite marking at the same time its priority.
In the same manner as seen before, we can move our sprite absolutely:
void move_sprite(UINT8 nb, UINT8 x, UINT8 y);
... or relatively...
void scroll_sprite(INT8 nb, INT8 x, INT8 y);
There are also attributes specific to sprites that can be used to reduce memory consumption. For instance, we can easily change the pallet we use to color our sprite or spin it to give the impression of a new design or eventually change the sprite priority, but it will not be discussed here. More info are available here:
https://blog.flozz.fr/2019/02/05/developpement-gameboy-7-les-sprites/