Drawing and Moving Sprites in Gameboy Games

This is part 3 of my “How to make a Gameboy Game” tutorial series. If you haven’t read part 1 or part 2 yet, you can find it here. In part 1, a minimal GBDK template was used. In part 2, we drew a basic background . In part 3, we’ll draw and move gameboy sprites.

This step will build on our minimal GBDK template:

				
					#include <gb/gb.h>

void main(void)
{
    DISPLAY_ON;

    // Loop forever
    while(1) {

		// Done processing, yield CPU and wait for start of next frame
        wait_vbl_done();
    }
}
				
			

In the above code, we just include the GBDK  “gb” library and turn the display on. After that we loop forever, and do nothing (of importance) that loop.

Table of Contents

Creating our gameboy sprites with GBTD

One of my current preferred tools for creating Gameboy graphics is GBTD and GBMD. Only GBTD will be needed for this step. GBTD stands for Gameboy Tile Designer. Here are some links to where they can be found.

For this step, i will keep it simple and just create a basic 8×8 sprite in GBTD. We will export the sprite into the same directory as our project.

GBTD simple sprite

Once, i’ve designed this to my liking, will export it for GBDK. This can be done using the “Export” or “Export To…” option in the file menu.

Export Simple Sprite from GBTD

With these settings, my sprite will be exported as a SimpleSprite.c and SimpleSprite.h file. The SimpleSprite.c file will contain the data for my gameboy sprites in a variable also called “SimpleSprite”. The variable name can be different from the filename if desired.

Here is what the contents of the SimpleSprite.c look like:

				
					/*

 SIMPLESPRITE.C

 Tile Source File.

 Info:
  Form                 : All tiles as one unit.
  Format               : Gameboy 4 color.
  Compression          : None.
  Counter              : None.
  Tile size            : 8 x 8
  Tiles                : 0 to 0

  Palette colors       : None.
  SGB Palette          : None.
  CGB Palette          : None.

  Convert to metatiles : No.

 This file was generated by GBTD v2.2

*/

/* Start of tile array. */
unsigned char SimpleSprite[] =
{
  0x3C,0x3C,0x3C,0x66,0xFF,0xFF,0xFF,0xBD,
  0xFF,0xBD,0xFF,0xFF,0x3C,0x66,0x3C,0x3C
};

/* End of SIMPLESPRITE.C */

				
			

If you want to understand what all this means more, please checkout our tutorial on Sprites and Backgrounds in GBDK 2020

Enabling Gameboy Sprites

This is a quick step. By default, sprites are NOT enabled. However, GBDK has a very simple way to enable them. All you need is the “SHOW_SPRITES” preprocessor directive. Alternatively, we can use “HIDE_SPRITES” to hide all sprites. We will execute this line of code right after we turn on the display.

				
					#include <gb/gb.h>

void main(void)
{
    DISPLAY_ON;
    SHOW_SPRITES;

    // Loop forever
    while(1) {

		// Done processing, yield CPU and wait for start of next frame
        wait_vbl_done();
    }
}
				
			

At this point in time, nothing will be shown on the screen. We still need to to do a couple more things.

Adding the sprite to our project.

Our program, as is, will NOT be able to detect our SimpleSprite. We need to include the GBTD created SimpleSprite.h in our main.c file, and also add the SimpleSprite.c to be compiled and used for .gb file creation.

				
					#include <gb/gb.h>
#include "SimpleSprite.h"

void main(void)
{
    DISPLAY_ON;
    SHOW_SPRITES;

    // Loop forever
    while(1) {

		// Done processing, yield CPU and wait for start of next frame
        wait_vbl_done();
    }
}
				
			

After adding our include to the main.c, we need to update our make.bat file. First, we are going to add a line compiling our SimpleSprite.c file into a .o file.

				
					C:\gbdk\bin\lcc -c -o SimpleSprite.o SimpleSprite.c
				
			

Next we are going to update where our .gb file is created. We want to to LCC (our gbdk compiler) to include the previously created SimpleSprite.o.

				
					C:\GBDK\bin\lcc  -o HandlingSpritesInGBDK.gb main.o SimpleSprite.o
				
			

The final product should look like this.

				
					REM delete previous files
DEL *.gb

REM compile .c files into .o files
C:\gbdk\bin\lcc -c -o main.o main.c
C:\gbdk\bin\lcc -c -o SimpleSprite.o SimpleSprite.c

REM Compile a .gb file from the compiled .o files
C:\GBDK\bin\lcc  -o HandlingSpritesInGBDK.gb main.o SimpleSprite.o

REM delete intermediate files created for the conmpilation process
DEL *.asm
DEL *.lst
DEL *.ihx
DEL *.sym
DEL *.o

				
			

Our project is now ready to show our SimpleSprite. However, like in previous steps, if you compile and run your .gb file nothing will actually be shown .

Showing our Sprite

Adding the sprite's tile data to VRAM

With our project ready to show our SimpleSprite the next step is adding the sprite’s tiledata into VRAM. This itself is also a quick step. More information about VRAM can be found in my article about understanding gameboy graphics.

For this next step, add the following line to the main.c file BEFORE the while loop.

				
					set_sprite_data(0,1,SimpleSprite);
				
			

The “set_sprite_data” function is the sprite equivalent of “set_bkg_data”. It is used to place tiles into VRAM, and  it takes 3 parameters:

  1. Which tile should we start at?
  2. How many tiles are we placing?
  3. A pointer to the GBTD exported tiledata. (Defined in SimpleSprite.c)

In my above script, I am placing 1 tile at the first spot in VRAM. Specifically, in the sprites section of VRAM.

				
					#include <gb/gb.h>
#include "SimpleSprite.h"

void main(void)
{
    DISPLAY_ON;
    SHOW_SPRITES;
    
    set_sprite_data(0,1,SimpleSprite);

    // Loop forever
    while(1) {

		// Done processing, yield CPU and wait for start of next frame
        wait_vbl_done();
    }
}
				
			

After this step, our .gb file STILL wont render anything to the gameboy’s screen. HOWEVER, if you can take at the VRAM you will see our sprite’s tile.

Simple Sprite in Gameboy VRAM

Choosing our sprite & it's tile

With our tile in VRAM, we just need to tell the gameboy which sprite to use to draw it. The gameboy can render up to 40 sprites at a given time. Place the following two lines of code right after the “set_sprite_data” line

				
					set_sprite_tile(0,0);
move_sprite(0,84,88);
				
			

In the above two lines of code do two things:

  • tell the gameboy that the first sprite (sprite 0), uses the first tile (tile 0) in sprite VRAM.
  • move the first sprite to center screen.

Moving the sprite to 84,88 is necessary this time. Sprites draw at 0,0 or above 160,160 will not be rendered. Now, for the first time in this tutorial, when you compile your .gb file something should show on screen.

Simple Sprite on Gameboy Screen

Sprite Properties and Color

Each sprite for gameboy games have a set of flags that can be toggled.

  • Priority – Should the sprites appear BEHIND the background and window. Normally, sprites appear on top of them both.
  • Vertical Flip – Should we flip our sprite’s tile verically?
  • Horizontal Flip – Should we flip our sprite’s tile horizontally?
  • Which Black & White Palette to use – (for GBC games running on Non-GBC consoles)
  • Which Color (and Bank) Palette to use (for GBC games only)

NOTE: Non-GBC consoles have 2 sprite color palettes, where color 0 is always transparent. By default in GBDK-2020 palette 0 (OBP0) is WHITE (color 0), LIGHT GREY, DARK GREY, BLACK (color 3), and palette 1 (OBP1) has the colors set to the inverse order. The colors can be changed using the DMG_PALETTE()  macro.

All of these are set using the same function “set_sprite_prop”. This function takes in two arguments:

  1. Which sprite, from 0-39
  2. A number, who’s bit’s represent the values for the flags above.

NOTE: The code below is not a part of the tutorial, and NOT required for showing a sprite. It’s purpose is just to give example:

				
					// 0 would mean:
//      - Above both window and background
//      - NOT vertically flipped
//      - NOT horizontally flipped
//      - Using the first B&W palette (if GBC game running on Non-GBC console)
//      - Using color palette 0 from bank 0 (if GBC)
set_sprite_prop(0,0);
				
			

If bit 7 is the left most bit, and bit 0 is the right most bit:

  • Bit 7 – when 1, enables the priority flag. Which puts that sprite below the background and window.
  • Bit 6 – when 1, flips the sprite vertically.
  • Bit 5 –  when 1, flips the sprite horizontally.
  • Bit 4 – Which black and white color palette (0 or 1) should be used, if a GBC color compatible game is running on a regular gameboy. (GBC Only)
  • Bit 3 – Which bank (0 or 1) of Sprite Tile Patterns the tile is taken. (GBC Only)
  • Bits 2-0 – Which of the 8 sprite color palettes should this sprite use. (GBC Only)

Making the sprite move.

A static sprite is no fun, so let’s add some motion. Were going to make the sprite bounce off the screens edges. There are three primary ways of changing a sprite’s location:

  1. The “scroll_sprite” function – This moves the sprite in the direction specified.
  2. The “move_sprite” function – This repositions the sprite at the given location.
  3. Directly changing the sprites location via it’s matcing “shadow_OAM” array item.

In this step were just going to use the “move_sprite” function.  But first we need to create 4 variables. We will declare these variables above our main function. Were going to create 2 variables to represent our sprite’s position, and two more variables to represent it’s movement.

				
					uint8_t spriteX,spriteY;
int8_t velocityX,velocityY;
				
			

Next, in our main function (before the while loop), we are going to initialize those variables.

				
					// Set the sprite's default position
spriteX=80;
spriteY=72;

// Set our default velocity to be down and to the right
velocityX=1;
velocityY=1;
				
			

The variables to represent movement, velocityX & velocityY, need to be int8_t’s. So our sprite can move left and upward. A normal uint8_t ranges from 0 to 255, and an int8_t can range from -127 to 127. A negative velocityX variable will move our sprite to the left. A negative velocityY variable will move our variable upwards.

Our while loop has been nearly up until now. Let’s add the final code to make the sprite move and bounce.

Our game’s entry point is very generic. It draws many similarities to the entry point in our How to make Flappy Bird for the Nintendo Gameboy tutorial.  First we enable sound, turn on our display, and show the background & sprites.

We’ll split our game into different game states.  Each of which will have their own setup and update functions. Each game state’s update function will return what game state to go to next.

In addition, we’ll fade our screen out and in when changing game stats.

				
					// Apply our velocity
spriteX+=velocityX;
spriteY+=velocityY;

// When we get too far to the right while moving to the right
if(spriteX>156&&velocityX>0){

    // Switch directions for our x velocity
    velocityX=-velocityX;

    // Clamp our x position back down to 156 so we don't go past the edge
    spriteX=156;
}

// When we get too far down on the screen while moving downards
if(spriteY>140&&velocityY>0){

    // Switch directions for our y velocity
    velocityY=-velocityY;

    // Clamp our y position back down to 140 so we don't go past the edge
    spriteY=140;
}

// When we get too far to the left while moving left
if(spriteX<4&&velocityX<0){

    // Switch directions for our x velocity
    velocityX=-velocityX;

    // Clamp our x position back up to 4 so we don't go past the edge
    spriteX=4;
}

// When we get too far towards the top of the screen while moving upwards
if(spriteY<4&&velocityY<0){

    // Switch directions for our y velocity
    velocityY=-velocityY;

    // Clamp our y position back up to 4 so we don't go past the edge
    spriteY=4;
}

// Position the first sprite at our spriteX and spriteY
// All sprites are render 8 pixels to the left of their x position and 16 pixels ABOVE their actual y position
// This means an object rendered at 0,0 will not be visible
// x+5 and y+12 will center the 8x8 tile at our x and y position
move_sprite(0,spriteX+4,spriteY+12);
				
			

That’s it! Once you compile and run the .gb file, the sprite should move around the screen. Here’s our final main.c:

				
					#include <gb/gb.h>
#include "SimpleSprite.h"

uint8_t spriteX,spriteY;
int8_t velocityX,velocityY;

void main(void)
{
    DISPLAY_ON;
    SHOW_SPRITES;

    set_sprite_data(0,1,SimpleSprite);
    set_sprite_tile(0,0);
    move_sprite(0,84,88);

    // Set our default position
    spriteX=80;
    spriteY=72;

    // Set our default velocity to be moving down and to the right
    velocityX=1;
    velocityY=1;

    // Loop forever
    while(1) {

        // Apply our velocity
        spriteX+=velocityX;
        spriteY+=velocityY;

        // When we get too far to the right while moving to the right
        if((spriteX>156)&&(velocityX>0)){

            // Switch directions for our x velocity
            velocityX=-velocityX;

            // Clamp our x position back down to 156 so we don't go past the edge
            spriteX=156;
        }

        // When we get too far down on the screen while moving downards
        if((spriteY>140)&&(velocityY>0)){

            // Switch directions for our y velocity
            velocityY=-velocityY;

            // Clamp our y position back down to 140 so we don't go past the edge
            spriteY=140;
        }

        // When we get too far to the left while moving left
        if((spriteX<4)&&(velocityX<0)){

            // Switch directions for our x velocity
            velocityX=-velocityX;

            // Clamp our x position back up to 4 so we don't go past the edge
            spriteX=4;
        }

        // When we get too far towards the top of the screen while moving upwards
        if((spriteY<4)&&(velocityY<0)){

            // Switch directions for our y velocity
            velocityY=-velocityY;

            // Clamp our y position back up to 4 so we don't go past the edge
            spriteY=4;
        }

        // Position the first sprite at our spriteX and spriteY
        // All sprites are render 8 pixels to the left of their x position and 16 pixels ABOVE their actual y position
        // This means an object rendered at 0,0 will not be visible
        // x+5 and y+12 will center the 8x8 tile at our x and y position
        move_sprite(0,spriteX+4,spriteY+12);

		// Done processing, yield CPU and wait for start of next frame
        wait_vbl_done();
    }
}

				
			

Check our the full code on our Github here. Here is our final result:

Simple Sprite Bouncing in Gameboy Gif 

Thanks for reading. If you found this helpful, please share it online to help promote Larold’s Jubilant Junkyard. If you have any questions, please don’t hesitate to reach out and ask questions. Your questions will help improve the Junkyard, so it’s a win-win situation.