Mastodon
Table of Contents
How to handle joypad input in GBDK
Player input is an important part of games. Itā€™s what separates games from videos. In step 4, we are going to draw a sprite to the screen and give the player control over that sprite.
Table of Contents

How to handle Gameboy Joypad input

How to handle Gameboy Joypad input

In this step of my How to make a Gameboy Game tutorial, we are going to give the player the ability to move a sprite around the screen. This tutorial will take a lot from the Drawing and Moving Sprites in Gameboy GamesĀ tutorial, so be sure you’ve taken a look at that one too.

Here’s what we are going to start with for this tutorial. We have our SimpleSprite.c from the previous tutorial on Drawing & Moving sprites, and this is our main.c:

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

uint8_t spriteX,spriteY;
int8_t velocityX,velocityY;
uint8_t joypadCurrent=0,joypadPrevious=0;

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=0;
    velocityY=0;

    // Loop forever
    while(1) {

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

        // 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();
    }
}

				
			

GBDK makes handling joypad input a really easy task. It’s “joypad” function does all the work, and returns an easily usable result. We can compare the result of this function with MACROS defined for user input. GBDK defines macros for each of the gameboys buttons:

  • J_UP
  • J_DOWN
  • J_RIGHT
  • J_LET
  • J_A
  • J_B
  • J_START
  • J_SELECT

To test if a button is down, we simply perform a bitwise and operation with the result of the joypad() function.

Here is an generic example:

				
					// If the right button on the d-pad is held down
if(joypad() & J_RIGHT){

    // Positive x velocity to move the sprite to the right
    velocityX=1;
}
				
			

When the right direction on the d-pad is held down, the above if-statement will set the x velocity to be 1, effectively moving our sprite to the right. Let’s handle moving the sprite to the left also.

IMPORTANT!

You should never call the joypad() function more than once per frame. Since we need to test both directions (left and right), we’ll save the output of the joypad function in a variable named “joypadCurrent”. We’ll use that variable if our if/else statement instead of the function directly.

				
					// We'll need to check the joypad input twice
// never call "joypad()" more than once per frame
// We'll save it's old value in our joypadPrevious variable
// We'll save it's new value and check that variable
joypadPrevious=joypadCurrent;
joypadCurrent = joypad();
        
// If the right button on the d-pad is held down
if(joypadCurrent & J_RIGHT){

    // Positive x velocity to move the sprite to the right
    velocityX=1;
    
// If the right button on the d-pad is held down
}else if(joypadCurrent & J_LEFT){

    // negative x velocity to move the sprite to the left
    velocityX=-1;
}
				
			

If we add this into our while loop, the sprite will move left and right. However, there is one thing we forgot. What if we are not holding left, AND we are not holding right? In this case, we want to stop the sprite from moving horizontally. All we need is a final else-statement where we set the velocityX variable to 0.

				
					// We'll need to check the joypad input twice
// never call "joypad()" more than once per frame
// We'll save it's old value in our joypadPrevious variable
// We'll save it's new value and check that variable
joypadPrevious=joypadCurrent;
joypadCurrent = joypad();

// If the right button on the d-pad is held down
if(joypadCurrent & J_RIGHT){

    // Positive x velocity to move the sprite to the right
    velocityX=1;
    
// If the right button on the d-pad is held down
}else if(joypadCurrent & J_LEFT){

    // negative x velocity to move the sprite to the left
    velocityX=-1;
}else{

    // Zero x velocity means no horizontal movement
    velocityX=0;
}
				
			

That should do it for basic movement. Here is what your main.cĀ  file should look like:

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

uint8_t spriteX,spriteY;
int8_t velocityX,velocityY;
uint8_t joypadCurrent=0,joypadPrevious=0;

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=0;
    velocityY=0;

    // Loop forever
    while(1) {
    
        // We'll need to check the joypad input twice
        // never call "joypad()" more than once per frame
        // We'll save it's current value and check that variable
        joypadPrevious=joypadCurrent;
        joypadCurrent = joypad();
    
        // If the right button on the d-pad is held down
        if(joypadCurrent & J_RIGHT){
        
            // Positive x velocity to move the sprite to the right
            velocityX=1;
            
        // If the right button on the d-pad is held down
        }else if(joypadCurrent & J_LEFT){
        
            // negative x velocity to move the sprite to the left
            velocityX=-1;
        }else{
        
            // Zero x velocity means no horizontal movement
            velocityX=0;
        }

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

        // 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();
    }
}

				
			

What about "tapping" buttons?

Often you only want to perform a specific action, when a button is “tapped”. That is, the first time is pressed, not just when it’s held down. This can be handled for all buttons using one extra variable.

You might of noticed previously, there was a variable created named “joypadPrevious”. Before we saved the “joypadCurrent” variable, we would update the “joypadPrevious” variable.

				
					// We'll need to check the joypad input twice
// never call "joypad()" more than once per frame
// We'll save it's current value and check that variable
joypadPrevious=joypadCurrent;
joypadCurrent = joypad();
				
			

Now that we’ve done that, we can use it. We can check if a buttonĀ  was “tapped” similar to how we determine if a button is held down. Using a bitwise and operation. However, for “tapping” we want to negate the result and compare against the normal joypad() function.

Let’s use the A & B buttons to move the sprite downward and upward respectively.

				
					// If the "A" button was just pressed
if(joypadCurrent & J_A) && !(joypadPrevious & J_A)){

    // Move the sprite downward
    spriteY+=8;
    
// If the "B" button was just presssed
} else if(joypadCurrent & J_B) && !(joypadPrevious & J_B)){

    // Move the sprite up
    spriteY-=8;
}
				
			

That’s it for basic input. Here is our final main.c file:

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

uint8_t spriteX,spriteY;
int8_t velocityX,velocityY;
uint8_t joypadCurrent=0,joypadPrevious=0;

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=0;
    velocityY=0;

    // Loop forever
    while(1) {
    
        // We'll need to check the joypad input twice
        // never call "joypad()" more than once per frame
        // We'll save it's current value and check that variable
        joypadPrevious=joypadCurrent;
        joypadCurrent = joypad();
    
        // If the right button on the d-pad is held down
        if(joypadCurrent & J_RIGHT){
        
            // Positive x velocity to move the sprite to the right
            velocityX=1;
            
        // If the right button on the d-pad is held down
        }else if(joypadCurrent & J_LEFT){
        
            // negative x velocity to move the sprite to the left
            velocityX=-1;
        }else{
        
            // Zero x velocity means no horizontal movement
            velocityX=0;
        }
        
        // If the "A" button was just pressed
        if((joypadCurrent & J_A) && !(joypadPrevious & J_A)){
        
            // Move the sprite downward
            spriteY+=8;
            
        // If the "B" button was just presssed
        } else if((joypadCurrent & J_B) && !(joypadPrevious & J_B)){
        
            // Move the sprite up
            spriteY-=8;
        }

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

        // 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();
    }
}

				
			

I hope that was clear and helps you in your Gameboy game development journeys. As always, if you found this helpful please do mention the Junkyard on social media. It helps a lot. If you have any questions, please don’t hesitate to reach out. Your feedback helps The Junkyard improve, so tutorials can be clear and helpful.

The source code for this tutorial, and all other tutorials, can be found on our Github page: https://github.com/LaroldsJubilantJunkyard

My Game Boy tutorials have a lot of C Programming. If you need help, here’s a book that may help you:
Who else is making Game Boy Games?

There are many individuals who are developing games for retro consoles. Here’s one you might like:

GB Wordyl

Created By: bbbbr

A portable word game that tests your skill! Use strategy and knowledge to guess the hidden word within 6 tries!

Other Tutorials:

Sign-Up for the "Junkyard Newsletter" for more Game Boy news!

If you like Game Boy Game Development, subscribe to the Junkyard Newsletter. Stay up-to-date with all the latest Game Boy news. It’s free, and you can unsubscribe any time!