Tips:Controller Event Handling

From Uzebox Wiki
Jump to: navigation, search

Overview

When handling controller button presses, there are some subtleties involved that may elude the first-time Uzebox programmer. In short, there are several kinds of button presses that we all use in video games, but may not be aware of how to translate them into code. This tutorial covers the three basic kinds of button events, and provides a basic template from which to build your own button handler.

API Details

Experienced Uzebox programmers may want to skip to the next section.

The Uzebox Kernel provides a very simple API to handle controller events. In short, you call ReadJoypad() with the logical controller number you're interested in. We say "logical controller number" as the physical controller #1 is referenced as logical number 0, and likewise, controller #2 is logical 1.

The ReadJoypad() function returns an int that contains the state of each button on the controller; 1 bit for each button. The API has a series of named flags to make figuring this out very easy. Simply logical-and the button value with the flag value to determine if the corresponding button is pressed:

int buttons = ReadJoypad(0); // get the button state for controller 1 (logical 0)
if(buttons & BTN_A){
    // do something if player presses "A"
}

The complete list of controller flags is defined as in the following table:

#define BTN_SR	   2048
#define BTN_SL	   1024
#define BTN_X	   512
#define BTN_A	   256
#define BTN_RIGHT  128
#define BTN_LEFT   64
#define BTN_DOWN   32
#define BTN_UP     16
#define BTN_START  8
#define BTN_SELECT 4
#define BTN_Y      2
#define BTN_B      1

Controller Events

Most of the time, it is enough to test if a button is being pressed at this moment in time.

int buttons = ReadJoypad(0);
if(buttons & BTN_A){
    // do something if player presses "A"
}

This tests if the button was pressed when the current frame started. If the player keeps button A depressed, then the action is taken for every frame until the button is released. Sometimes, this is appropriate but not always. Other times, you need to be able to detect if the player has released or pressed the button this frame, and this frame only.

For when we want to see these controller "events" - pressing and releasing a button - the following pattern can be used:

int btnHeld = 0;     // buttons that are held right now
int btnPressed = 0;  // buttons that were pressed this frame
int btnReleased = 0; // buttons that were released this frame 

int main(){
    while(1){
        WaitVsync(1);
    
        btnHeld = ReadJoypad(0);
        btnPressed = btnHeld & (btnHeld ^ btnPrev);
        btnReleased = btnPrev & (btnHeld ^ btnPrev);
    
        if(btnPressed & BTN_A){
            // do something if player pressed "A"
        }
        if(btnReleased & BTN_B){
            // do something if player released "B"
        }
        if(btnHeld & BTN_RIGHT){
            // do something if player is holding "RIGHT"
        }
        btnPrev = btnHeld;
    }
}

The code above captures the press and release events by looking at the transition of button state from the previous frame to the current frame.