Larold’s Jubilant Junkyard” has become “Larold’s Retro Gameyard“. I’ve been working on this re-branding and migration for a while. All old tutorials should redirect you to this new site. If you see any errors, please let me know! See here for more information: What happened to Larold’s Jubilant Junkyard?

How to handle Gameboy Joypad input

How to handle Gameboy Joypad input

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.

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

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

Leave a Reply

Your email address will not be published. Required fields are marked *

THANKS FOR READING!

If you have any suggestions, and/or are confused about anything: feel free to leave a comment, send me a email, or a message on social media. Constructive criticism will help the gameyard, and others like yourself. If you learned something from this tutorial, and are looking for more content, check other these other tutorials. 

How to handle Gameboy Joypad input

Thanks for reading my tutorial, here are the files for that tutorial. 

Download Instructions

Unzip the attached zip file. You’ll need GBDK-2020 downloaded on your computer.  Update the GBDK_HOME environment variable in the make.bat file, then run the make.bat file from the command line/terminal.

If you want to make/request changes for the code, you can send me an email or put in a PR request on GitHub. Here’s a GitHub link for the code below.

Sign-Up for the "Gameyard Newsletter" for MOre Game Development News

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

Be sure to check your email inbox for a confirmation email.