New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved controller support; migrated to SDL_GameController API #96

Merged
merged 2 commits into from Nov 1, 2016
Jump to file or symbol
Failed to load files and symbols.
+101 −72
Diff settings

Always

Just for now

Next

Improved controller support; migrated to SDL_GameController API

This improves the controller support in several ways, based on suggestions and earlier work by @EndeavourAccuracy and others:
* Migrated to the SDL_GameController API, which gives an abstraction layer over the controller mappings and may thus provide better compatibility with different controllers.
* Buttons and joysticks on the controller no longer interfere with each other's input (each button or axis should have its own state variable)
* Works with the joystick's angle instead of raw X/Y cutoffs
* In general, tweaked the responsiveness of the joystick controls - playing with a controller should be more pleasant. (tested using an Xbox 360 controller)
* Can now also use the triggers (both left and right) as Shift control.
* Start button now restarts the game (Similar to Ctrl+R), Back button restarts the level (Similar to Ctrl+A).
  • Loading branch information...
Falcury committed Oct 29, 2016
commit e7ec4cc69ac65c24f3cd958559f1b109e47feb8e
View
@@ -524,9 +524,14 @@ extern SDL_Surface* onscreen_surface_;
extern SDL_Renderer* renderer_;
extern SDL_Window* window_;
extern SDL_Texture* sdl_texture_;
extern SDL_Joystick* sdl_controller_ INIT( = 0 );
extern int gamepad_states[3] INIT( = { 0, 0, 0 } ); // hor, ver, shift
extern SDL_GameController* sdl_controller_ INIT( = 0 );
extern int joy_axis[6]; // hor/ver axes for left/right sticks + left and right triggers (in total 6 axes)
extern int joy_left_stick_states[2]; // horizontal, vertical
extern int joy_right_stick_states[2];
extern int joy_hat_states[2]; // horizontal, vertical
extern int joy_AY_buttons_state;
extern int joy_X_button_state;
extern int screen_updates_suspended;
View
@@ -1106,23 +1106,77 @@ void __pascal far check_fall_flo() {
}
}
void get_joystick_state(int raw_x, int raw_y, int axis_state[2]) {
#define JOY_THRESHOLD 8000
#define DEGREES_TO_RADIANS (M_PI/180.0)
// check if the X/Y position is within the 'dead zone' of the joystick
if ((raw_x*raw_x + raw_y*raw_y) < JOY_THRESHOLD*JOY_THRESHOLD) {
axis_state[0] = 0;
axis_state[1] = 0;
} else {
double angle = atan2(raw_y, raw_x); // angle of the joystick: 0 = right, >0 = downward, <0 = upward
//printf("Joystick angle is %f degrees\n", angle/DEGREES_TO_RADIANS);
if (fabs(angle) < (60*DEGREES_TO_RADIANS)) // 120 degree range facing right
axis_state[0] = 1;
else if (fabs(angle) > (120*DEGREES_TO_RADIANS)) // 120 degree range facing left
axis_state[0] = -1;
else {
// joystick is neutral horizontally, so the control should be released
// however: prevent stop running if the Kid was already running / trying to do a running-jump
// (this tweak makes it a bit easier to do (multiple) running jumps)
if (!(angle < 0 /*facing upward*/ && Kid.action == actions_1_run_jump)) {
axis_state[0] = 0;
}
}
if (angle < (-30*DEGREES_TO_RADIANS) && angle > (-150*DEGREES_TO_RADIANS)) // 120 degree range facing up
axis_state[1] = -1;
// down slightly less sensitive than up (prevent annoyance when your thumb slips down a bit by accident)
// (not sure if this adjustment is really necesary)
else if (angle > (35*DEGREES_TO_RADIANS) && angle < (145*DEGREES_TO_RADIANS)) // 110 degree range facing down
axis_state[1] = 1;
else {
// joystick is neutral vertically, so the control should be released
// however: should prevent unintended standing up when attempting to crouch-hop
if (!(Kid.frame == frame_109_crouch && angle > 0 /*facing downward*/)) {
axis_state[1] = 0;
}
}
}
}
// seg000:1051
void __pascal far read_joyst_control() {
// stub
if (gamepad_states[0] == -1)
get_joystick_state(joy_axis[SDL_CONTROLLER_AXIS_LEFTX], joy_axis[SDL_CONTROLLER_AXIS_LEFTY], joy_left_stick_states);
get_joystick_state(joy_axis[SDL_CONTROLLER_AXIS_RIGHTX], joy_axis[SDL_CONTROLLER_AXIS_RIGHTY], joy_right_stick_states);
if (joy_left_stick_states[0] == -1 || joy_right_stick_states[0] == -1 || joy_hat_states[0] == -1)
control_x = -1;
if (gamepad_states[0] == 1)
if (joy_left_stick_states[0] == 1 || joy_right_stick_states[0] == 1 || joy_hat_states[0] == 1)
control_x = 1;
if (gamepad_states[1] == -1)
if (joy_left_stick_states[1] == -1 || joy_right_stick_states[1] == -1 || joy_hat_states[1] == -1 || joy_AY_buttons_state == -1)
control_y = -1;
if (gamepad_states[1] == 1)
if (joy_left_stick_states[1] == 1 || joy_right_stick_states[1] == 1 || joy_hat_states[1] == 1 || joy_AY_buttons_state == 1)
control_y = 1;
if (gamepad_states[2] == 1)
if (joy_X_button_state == 1 ||
joy_axis[SDL_CONTROLLER_AXIS_TRIGGERLEFT] > 8000 ||
joy_axis[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] > 8000)
{
control_shift = -1;
}
}
// seg000:10EA
View
@@ -606,7 +606,7 @@ int __pascal far set_joy_mode() {
if (SDL_NumJoysticks() < 1) {
is_joyst_mode = 0;
} else {
sdl_controller_ = SDL_JoystickOpen( 0 );
sdl_controller_ = SDL_GameControllerOpen(0);
if (sdl_controller_ == NULL) {
is_joyst_mode = 0;
} else {
@@ -1936,7 +1936,7 @@ int __pascal far check_sound_playing() {
// seg009:38ED
void __pascal far set_gr_mode(byte grmode) {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE | SDL_INIT_JOYSTICK ) != 0) {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE | SDL_INIT_GAMECONTROLLER ) != 0) {
sdlperror("SDL_Init");
quit(1);
}
@@ -2593,75 +2593,45 @@ void idle() {
case SDL_KEYUP:
key_states[event.key.keysym.scancode] = 0;
break;
case SDL_CONTROLLERAXISMOTION:
if (event.caxis.axis < 6) joy_axis[event.caxis.axis] = event.caxis.value;
break;
case SDL_CONTROLLERBUTTONDOWN:
switch (event.cbutton.button)
{
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: joy_hat_states[0] = -1; break; // left
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: joy_hat_states[0] = 1; break; // right
case SDL_CONTROLLER_BUTTON_DPAD_UP: joy_hat_states[1] = -1; break; // up
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: joy_hat_states[1] = 1; break; // down
case SDL_JOYAXISMOTION:
if (event.jaxis.axis == 0) {
if (event.jaxis.value < -8000)
gamepad_states[0] = -1; // left
else if (event.jaxis.value > 8000)
gamepad_states[0] = 1; // right
else
gamepad_states[0] = 0;
}
case SDL_CONTROLLER_BUTTON_A: joy_AY_buttons_state = 1; break; /*** A (down) ***/
case SDL_CONTROLLER_BUTTON_Y: joy_AY_buttons_state = -1; break; /*** Y (up) ***/
case SDL_CONTROLLER_BUTTON_X: joy_X_button_state = 1; break; /*** X (shift) ***/
if (event.jaxis.axis == 1) {
if (event.jaxis.value < -8000)
gamepad_states[1] = -1; // up
case SDL_CONTROLLER_BUTTON_START:
last_key_scancode = SDL_SCANCODE_R | WITH_CTRL; /*** start (restart game) ***/
break;
else if (event.jaxis.value > 8000)
gamepad_states[1] = 1; // down
case SDL_CONTROLLER_BUTTON_BACK:
last_key_scancode = SDL_SCANCODE_A | WITH_CTRL; /*** back (restart level) ***/
break;
else
gamepad_states[1] = 0;
default: break;
}
break;
case SDL_JOYHATMOTION:
switch (event.jhat.value)
case SDL_CONTROLLERBUTTONUP:
switch (event.cbutton.button)
{
case 1: gamepad_states[1] = -1; break; // up
case 2: gamepad_states[0] = 1; break; // right
case 3: gamepad_states[0] = 1; gamepad_states[1] = -1; break; // right (and up)
case 4: gamepad_states[1] = 1; break; // down
case 6: gamepad_states[0] = 1; gamepad_states[1] = 1; break; // right (and down)
case 8: gamepad_states[0] = -1; break; // left
case 9: gamepad_states[0] = -1; gamepad_states[1] = -1; break; // left (and up)
case 12: gamepad_states[0] = -1; gamepad_states[1] = 1; break; // left (and down)
default: gamepad_states[0] = 0; gamepad_states[1] = 0; break;
}
break;
case SDL_JOYBUTTONDOWN:
switch (event.jbutton.button)
{
case 0: gamepad_states[1] = 1; break; /*** A (down) ***/
case 1: break; /*** B ***/
case 2: gamepad_states[2] = 1; break; /*** X (shift) ***/
case 3: gamepad_states[1] = -1; break; /*** Y (up) ***/
case 4: break; /*** left shoulder ***/
case 5: break; /*** right shoulder ***/
case 6: break; /*** back ***/
case 7: quit(0); break; /*** start (quit) ***/
case 8: break; /*** guide ***/
case 9: break; /*** left joystick ***/
case 10: break; /*** right joystick ***/
}
break;
case SDL_JOYBUTTONUP:
switch (event.jbutton.button)
{
case 0: gamepad_states[1] = 0; break; /*** A (down) ***/
case 1: break; /*** B ***/
case 2: gamepad_states[2] = 0; break; /*** X (shift) ***/
case 3: gamepad_states[1] = 0; break; /*** Y (up) ***/
case 4: break; /*** left shoulder ***/
case 5: break; /*** right shoulder ***/
case 6: break; /*** back ***/
case 7: break; /*** start ***/
case 8: break; /*** guide ***/
case 9: break; /*** left joystick ***/
case 10: break; /*** right joystick ***/
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: joy_hat_states[0] = 0; break; // left
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: joy_hat_states[0] = 0; break; // right
case SDL_CONTROLLER_BUTTON_DPAD_UP: joy_hat_states[1] = 0; break; // up
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: joy_hat_states[1] = 0; break; // down
case SDL_CONTROLLER_BUTTON_A: joy_AY_buttons_state = 0; break; /*** A (down) ***/
case SDL_CONTROLLER_BUTTON_Y: joy_AY_buttons_state = 0; break; /*** Y (up) ***/
case SDL_CONTROLLER_BUTTON_X: joy_X_button_state = 0; break; /*** X (shift) ***/
default: break;
}
break;
case SDL_TEXTINPUT:
ProTip! Use n and p to navigate between commits in a pull request.