Mapping data to game controls
In the update() function, the information retrieved from gamepad and joystick events is used to refresh the application's state.
To determine the state of the analog sticks, we use the data retrieved by querying the SCREEN_PROPERTY_ANALOG0 and SCREEN_PROPERTY_ANALOG1 properties. Here, it's useful to note that the analog0 and analog1 members of the GameController struct are arrays of three integers and not two integers. The third integer is used by some input devices that use the SCREEN_EVENT_JOYSTICK type, and may be used in the future to support analog triggers. For most game controllers, we're interested in the first two values only. These values correspond to the horizontal and vertical axis of an analog stick respectively, and range between -128 and +127, with a value of (0, 0) specifying that the stick is in its default position.
To determine the state of the buttons, each bit in the integer retrieved by querying SCREEN_PROPERTY_BUTTONS is decoded. Each bit is a flag representing a single button, which is set when that button is pressed down. The first twenty bits correspond to constants found in screen.h and these constants are mapped to buttons for the recommended controllers for this API. These constants are defined in an enumeration as follows:
enum {
SCREEN_A_GAME_BUTTON = (1 << 0),
SCREEN_B_GAME_BUTTON = (1 << 1),
SCREEN_C_GAME_BUTTON = (1 << 2),
SCREEN_X_GAME_BUTTON = (1 << 3),
SCREEN_Y_GAME_BUTTON = (1 << 4),
SCREEN_Z_GAME_BUTTON = (1 << 5),
SCREEN_MENU1_GAME_BUTTON = (1 << 6),
SCREEN_MENU2_GAME_BUTTON = (1 << 7),
SCREEN_MENU3_GAME_BUTTON = (1 << 8),
SCREEN_MENU4_GAME_BUTTON = (1 << 9),
SCREEN_L1_GAME_BUTTON = (1 << 10),
SCREEN_L2_GAME_BUTTON = (1 << 11),
SCREEN_L3_GAME_BUTTON = (1 << 12),
SCREEN_R1_GAME_BUTTON = (1 << 13),
SCREEN_R2_GAME_BUTTON = (1 << 14),
SCREEN_R3_GAME_BUTTON = (1 << 15),
SCREEN_DPAD_UP_GAME_BUTTON = (1 << 16),
SCREEN_DPAD_DOWN_GAME_BUTTON = (1 << 17),
SCREEN_DPAD_LEFT_GAME_BUTTON = (1 << 18),
SCREEN_DPAD_RIGHT_GAME_BUTTON = (1 << 19),
};
In the Gamepad application, the mapping of physical buttons on the device to virtual buttons on the screen is stored in the _buttons[] array, which is of type Button.
typedef struct Button_t {
// A button's type determines which set of UVs it uses.
ButtonType type;
int mapping;
Quad* quad;
char* label;
} Button;In
the init() function, the mapping member for each
Button is assigned one of the flags in the above enumeration to
uniquely identify the button. This member can be re-mapped at any time by tapping a
virtual button on the screen of the BlackBerry 10
device and then pressing the corresponding physical button on the gamepad.
if (controller->buttons & button->mapping) {
...
}Here,
controller->buttons is the integer retrieved using
screen_get_event_property_iv() and
SCREEN_PROPERTY_BUTTONS and button->mapping is
a single value from the enumeration above.
To check a single button at a time, rather than looping through a list of buttons as in the sample, you would do something like this:
if (controller->buttons & SCREEN_A_GAME_BUTTON)
{
/* The A button is currently down. */
}
if (controller->buttons & SCREEN_B_GAME_BUTTON) {
/* The B button is currently down. */
}
if ( ... ) { /* etc. */ }We
check each button individually as it's possible that more than one button is being
pressed.
Other considerations
When creating default button mappings for your game, it's important to remember that some controllers can be used in either portrait or landscape orientation, such as the Nintendo Wii Remote. This means that buttons that may be easy to reach in one orientation could be difficult to reach in another. For example, the A and B buttons for the Nintendo Wii Remote are mapped to the A and B buttons in the buttons enumeration but these are difficult to press when holding the controller in landscape orientation. You can make this easier for the player by mapping the X and Y buttons on the Nintendo Wii Remote to A and B in the buttons enumeration, respectively.
While analog sticks provide higher precision in movement, not all game controllers have them. To accomodate game controllers without analog sticks, consider designing your app to use the D-pad to perform the same actions.
That's all there is to it! The rest of the sample is dedicated to rendering graphics and re-mapping controls, which isn't necessary to understand the functions we've gone over above. Feel free to browse the code, change things up, and modify the app to try something different.