From d59f1536f8e7bc05acafc11944907de73f591996 Mon Sep 17 00:00:00 2001 From: Jason Woofenden Date: Thu, 5 May 2011 01:32:11 -0400 Subject: [PATCH] joysticks: configurable, working, buttons enable It works! Press a joystick button to enable that joystick. Here's why you need to enable the joystick: We don't want your ship to drift when you have a joystick plugged in and you're not using it, and it doesn't center perfectly. You can use the -j/--joystick option to specify which axes you'd like to use (I've tested it with a PlayStation 3 controller, I can use the tilt sensor to control VoR like this: vor -j 4,5 For those with axes but not any buttons (perhaps a handheld computer with an accelerometer) you can enable a joystick with by adding the joystick number (0 unless you have multiple joysticks) as the third parameter to the -j/--joystick flag, like this: vor --joystick=0,1,0 The argument parser is passed the following argv value unless there's a =. When parsing for your argument, you should barf if you get an invalid value that looks like it might be a flag (and tell the user they forgot to put in your argument.) The current parser will handle these forms: vor -j 0,1 vor --joystick=0,1 vor --joystick 0,1 Still need to make sensitivity adjustable and enable reversing axes. --- args.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- args.h | 4 +++ main.c | 72 +++++++++++++++++++++++++++++----------- 3 files changed, 166 insertions(+), 26 deletions(-) diff --git a/args.c b/args.c index 5056239..3ff1412 100644 --- a/args.c +++ b/args.c @@ -8,6 +8,10 @@ // Look and Feel int opt_fullscreen; int opt_sound; +int opt_joystick_enabled; +int opt_joystick_number; +int opt_joystick_x_axis; +int opt_joystick_y_axis; int opt_autopilot; @@ -17,19 +21,108 @@ show_help(void) puts("Dodge the rocks until you die."); putchar('\n'); puts(" -f, --full-screen"); - puts(" -s, --silent No explosion sounds or music"); - puts(" -V, --version Print program version"); - puts(" -?, --help Give this help list"); + puts(" -s, --silent No explosion sounds or music"); + puts(" -j x,y, --joystick=x,y set the axis numbers. defaults to 0,1"); + puts(" press a joystick button to activate that joystick"); + puts(" -V, --version Print program version"); + puts(" -?, --help Give this help list"); putchar('\n'); puts("Report bugs at http://jasonwoof.com/contact.html"); } +// Advances buf while reading a positive int, terminated by [^0-9] +// buf is left pointing at first [^0-9] +// If digits are found, the parsed number is written to *out and 0 is returned. +// Otherwise *buf and *out are left unchanged, and non-zero is returned. +int +parse_next_int(char **buf, int* out) { + int ret = 0, mul = 1; + if(!*buf) { + return 1; + } + // make sure *buf starts -?[0-9] + if(**buf == '-') { + mul = -1; + if((*buf)[1] < '0' || (*buf)[1] > '9') { + return 2; + } + *buf += 1; + } else { + if(**buf < '0' || **buf > '9') { + return 2; + } + } + while(**buf >= '0' && **buf <= '9') { + ret *= 10; + ret += **buf - '0'; + *buf += 1; + } + *out = ret * mul; + + return 0; +} + +// returns 1 on success. return 0 causes usage message +int +parse_joystick_opts(char *arg) { + char *arg_was = arg; + static char* bad_arg = "Error: invalid argument to -j/--joystick."; + + // argument is required + if(arg == NULL) { + puts(bad_arg); + return 0; + } + + // read x axis + if(parse_next_int(&arg, &opt_joystick_x_axis)) { + puts(bad_arg); + return 0; + } + + // skip comma + if(*arg != ',') { + puts(bad_arg); + return 0; + } + arg += 1; + + // read y axis + if(parse_next_int(&arg, &opt_joystick_y_axis)) { + puts(bad_arg); + return 0; + } + + // optionally joystick number + if(*arg == ',') { + arg += 1; // skip comma + if(parse_next_int(&arg, &opt_joystick_number)) { + puts(bad_arg); + return 0; + } + opt_joystick_enabled = 1; + } + + // end with a comma or end of string + if(*arg != 0 && *arg != ',') { + puts(bad_arg); + return 0; + } + + // mark arg as consumed (so it won't be parsed as a commandline switch) + arg_was[0] = 0; + + // return success + return 1; +} int short_opt(char c, char *arg) { switch(c) { case 'f': opt_fullscreen = 1; break; case 's': opt_sound = 0; break; + case 'j': + return parse_joystick_opts(arg); case 'V': printf("Variations on Rockdodger %s\n", PACKAGE_VERSION); exit(0); @@ -50,9 +143,9 @@ parse_short_opts(const char *s, char *arg) return short_opt(*s, arg); } -static char *long_opts[] = { "full-screen", "silent", "version", "help", "autopilot" }; +static char *long_opts[] = { "full-screen", "silent", "joystick", "version", "help", "autopilot" }; -static char short_opts[] = { 'f', 's', 'V', 'h', 'a' }; +static char short_opts[] = { 'f', 's', 'j', 'V', 'h', 'a' }; int parse_long_opt(const char *s, char *arg) @@ -71,6 +164,10 @@ init_opts(void) { opt_fullscreen = 0; opt_sound = 1; + opt_joystick_enabled = 0; // can also be enabled by pressing one of its buttons + opt_joystick_number = 0; + opt_joystick_x_axis = 0; + opt_joystick_y_axis = 1; opt_autopilot = 0; } @@ -83,6 +180,8 @@ parse_opts(int argc, char *argv[]) init_opts(); for(i=1; i 0) + num_joysticks = SDL_NumJoysticks(); +printf("num_joysticks: %i\n", num_joysticks); + if(num_joysticks) { - NULLERROR(joy = SDL_JoystickOpen(0)); + joysticks = (SDL_Joystick **)malloc(num_joysticks * sizeof(SDL_Joystick *)); + for(i = 0; i < num_joysticks; ++i) { + NULLERROR(joysticks[i] = SDL_JoystickOpen(i)); + } } init_dots(); @@ -686,8 +692,8 @@ gameloop() { SDL_Event e; Uint8 *keystate; Sint16 x_move, y_move; - char button_pressed; - short i; + char button_pressed = 0; + short i, j; float tmp; for(;;) { @@ -771,16 +777,40 @@ gameloop() { } } keystate = SDL_GetKeyState(NULL); - SDL_JoystickUpdate(); - x_move = SDL_JoystickGetAxis(joy, 4); - y_move = SDL_JoystickGetAxis(joy, 5); - button_pressed = 0; - for(i = 1; i <= SDL_JoystickNumButtons(joy); i++) - { - if(SDL_JoystickGetButton(joy, i) == 1) - { - button_pressed = 1; - break; + if(num_joysticks) { + SDL_JoystickUpdate(); + if(opt_joystick_enabled) { + x_move = SDL_JoystickGetAxis(joysticks[opt_joystick_number], opt_joystick_x_axis); + y_move = SDL_JoystickGetAxis(joysticks[opt_joystick_number], opt_joystick_y_axis); + button_pressed = 0; + for(i = 1; i <= SDL_JoystickNumButtons(joysticks[opt_joystick_number]); i++) + { + if(SDL_JoystickGetButton(joysticks[opt_joystick_number], i) == 1) + { + button_pressed = 1; + break; + } + } + } else { // there is at least one joystick, but it hasn't been enabled yet + // if any joystick has a button down, enable that joystick + for(j = 0; j <= num_joysticks; j++) { + for(i = 1; i <= SDL_JoystickNumButtons(joysticks[j]); i++) + { + if(SDL_JoystickGetButton(joysticks[j], i) == 1) + { + opt_joystick_enabled = 1; + opt_joystick_number = j; +printf("enabled joystick #%i\n", opt_joystick_number); + if(state != GAMEPLAY) { + // first (enabling) press of the joystick + // button should start a game, but should + // not pause a running game + button_pressed = 1; + } + break; + } + } + } } } @@ -804,10 +834,12 @@ gameloop() { if(keystate[SDLK_UP] || keystate[SDLK_KP8]) { ship.dy -= THRUSTER_STRENGTH*t_frame; ship.jets |= 1<<3; } - if(x_move < -3000) { ship.dx += x_move*THRUSTER_STRENGTH*t_frame/22768; ship.jets |= 1<<0;} - if(y_move > 3000) { ship.dy += y_move*THRUSTER_STRENGTH*t_frame/22768; ship.jets |= 1<<1;} - if(x_move > 3000) { ship.dx += x_move*THRUSTER_STRENGTH*t_frame/22768; ship.jets |= 1<<2;} - if(y_move < -3000) { ship.dy += y_move*THRUSTER_STRENGTH*t_frame/22768; ship.jets |= 1<<3;} + if(opt_joystick_enabled) { + if(x_move < -3000) { ship.dx += x_move*THRUSTER_STRENGTH*t_frame/22768; ship.jets |= 1<<0;} + if(y_move > 3000) { ship.dy += y_move*THRUSTER_STRENGTH*t_frame/22768; ship.jets |= 1<<1;} + if(x_move > 3000) { ship.dx += x_move*THRUSTER_STRENGTH*t_frame/22768; ship.jets |= 1<<2;} + if(y_move < -3000) { ship.dy += y_move*THRUSTER_STRENGTH*t_frame/22768; ship.jets |= 1<<3;} + } if(ship.jets) { ship.dx = fconstrain2(ship.dx, -50, 50); ship.dy = fconstrain2(ship.dy, -50, 50); @@ -920,7 +952,7 @@ main(int argc, char **argv) { frames = 0; gameloop(); end = SDL_GetTicks(); - // printf("%ld frames in %ld ms, %.2f fps.\n", frames, end-start, frames * 1000.0 / (end-start)); + printf("%ld frames in %ld ms, %.2f fps.\n", frames, end-start, frames * 1000.0 / (end-start)); return 0; } -- 1.7.10.4