From e9ea95d3b9568337f3a850f97cadb85898b5642a Mon Sep 17 00:00:00 2001 From: Jakub Skokan Date: Wed, 13 Jul 2016 09:22:21 +0200 Subject: [PATCH] Add support for game controllers --- src/game.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/game.h | 4 +++ src/main.cpp | 32 ++++++++++++++++++-- src/menu.cpp | 56 +++++++++++++++++++++++++++++++--- src/menu.h | 1 + src/player.cpp | 13 +++++++- src/player.h | 8 +++++ 7 files changed, 187 insertions(+), 8 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 3f230c5..773815c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -284,6 +284,50 @@ int Game::gameLoop() { // handle player controls updateControls(event.key.keysym.sym, false); + + } else if (event.type == SDL_CONTROLLERBUTTONUP) { + switch (event.cbutton.button) { + case SDL_CONTROLLER_BUTTON_A: + if (state == WAITFORSTART) { + state = START; + stateTimer = 0; + stateVal = 0; + } + break; + + case SDL_CONTROLLER_BUTTON_B: + case SDL_CONTROLLER_BUTTON_BACK: + case SDL_CONTROLLER_BUTTON_START: + loop = false; + break; + } + + } else if (event.type == SDL_CONTROLLERAXISMOTION) { + switch (event.caxis.axis) { + case SDL_CONTROLLER_AXIS_LEFTX: + updateControls( + mapControllerAxis( + event.caxis.which, + event.caxis.axis, + event.caxis.value + ), + event.caxis.value < -12000 || event.caxis.value > 12000 + ); + break; + + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + updateControls( + mapControllerAxis( + event.caxis.which, + event.caxis.axis, + event.caxis.value + ), + event.caxis.value > 500 + ); + break; + } + } } @@ -435,6 +479,43 @@ void Game::updateWorld(float t) } +SDL_Keycode Game::mapControllerAxis(SDL_JoystickID joy, Uint8 axis, Sint16 value) +{ + int ctrl; + + for(int i = 0; i < MAX_PLAYERS; i++) { + if (!players[i].hasController(joy)) + continue; + + // Controls in order: right, left, thrust + switch(axis) { + case SDL_CONTROLLER_AXIS_LEFTX: + ctrl = value > 0 ? 0 : 1; + break; + + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + ctrl = 2; + break; + + default: + return SDLK_ESCAPE; + } + + return CONTROLS[i][ctrl]; + } + + return SDLK_ESCAPE; +} + +int Game::getPlayerForController(SDL_JoystickID id) +{ + for(int p = 0; p < MAX_LOCAL_PLAYERS; p++) + if (players[p].hasController(id)) + return p; + return -1; +} + void Game::initViewports(int num) { numViewports = num; diff --git a/src/game.h b/src/game.h index ac0ae74..d8b1e81 100644 --- a/src/game.h +++ b/src/game.h @@ -37,6 +37,8 @@ public: Level &getLevel(); static Game &getInstance(); + + int getPlayerForController(SDL_JoystickID id); void initViewports(int num); @@ -59,6 +61,8 @@ private: bool updateControls(int keysym, bool down); void updateWorld(float t); + + SDL_Keycode mapControllerAxis(SDL_JoystickID joy, Uint8 axis, Sint16 value); void resetListener(); void updateListener(); diff --git a/src/main.cpp b/src/main.cpp index 815b7e2..89b2661 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include "SDL.h" #include "SDL_opengl.h" +//#include "SDL_gamecontroller.h" #include #include #include @@ -93,7 +94,7 @@ int main(int argc, char *argv[]) atexit(cleanup); - if(SDL_Init(SDL_INIT_VIDEO) != 0) + if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) != 0) { fprintf(stderr, "Can't initialize SDL: %s\n", SDL_GetError()); return -1; @@ -160,15 +161,40 @@ int main(int argc, char *argv[]) SDL_ShowCursor(SDL_DISABLE); Game &game = Game::getInstance(); + if(game.init(screen)) return 1; if(Menu::init()) return 1; + SDL_GameController *controllers[8] = {NULL}; + SDL_GameController *controller = NULL; + + for (int i = 0, j = 0; i < SDL_NumJoysticks(); i++) { + if (!SDL_IsGameController(i)) + continue; + + controller = SDL_GameControllerOpen(i); + + if (controller) { + controllers[j++] = controller; + + } else { + fprintf(stderr, "Could not open gamecontroller %i: %s\n", i, SDL_GetError()); + } + } + Menu menu(screen); while(1) { if(menu.show()) - return 0; + break; if(game.gameLoop()) - return 0; + break; + } + + for (int i = 0; i < 8; i++) { + if (!controllers[i]) + break; + + SDL_GameControllerClose(controllers[i]); } SDL_GL_DeleteContext(glcontext); diff --git a/src/menu.cpp b/src/menu.cpp index 18b749a..d814db3 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -101,6 +101,51 @@ int Menu::show() } } } + else if (event.type == SDL_CONTROLLERBUTTONUP) { + Game &game = Game::getInstance(); + + if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A ) { + int p; + + if ((p = game.getPlayerForController(event.cbutton.which)) == -1) { + // Activate the first available player + for(int p = 0; p < Game::MAX_LOCAL_PLAYERS; p++) { + Player &plr = Game::getInstance().getPlayer(p); + + if (plr.isActive()) + continue; + + togglePlayer(plr); + plr.setController(event.cbutton.which); + + break; + } + + } else { + // Player is already active, start the game + if (canstart) + rval = 0; + } + + } else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_B) { + // Find out if this joystick already belongs to a player + for(int p = 0; p < Game::MAX_LOCAL_PLAYERS; p++) { + Player &plr = game.getPlayer(p); + + if (plr.hasController(event.cbutton.which)) { + togglePlayer(plr); + break; + } + } + + } else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_START) { + if (canstart) + rval = 0; + + } else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK) { + rval = 1; + } + } } } @@ -109,12 +154,15 @@ int Menu::show() void Menu::togglePlayer(int p) { - Game &game = Game::getInstance(); - Player &plr = game.getPlayer(p); + togglePlayer(Game::getInstance().getPlayer(p)); +} + +void Menu::togglePlayer(Player &plr) +{ plr.setActive(!plr.isActive()); int act=0; - for(int plr=0;plr<4;plr++) { - if(game.getPlayer(plr).isActive()) + for(int p=0;p<4;p++) { + if(plr.isActive()) ++act; } canstart = act>0; diff --git a/src/menu.h b/src/menu.h index a8b0a3e..85849af 100644 --- a/src/menu.h +++ b/src/menu.h @@ -11,6 +11,7 @@ class Menu { int show(); private: void togglePlayer(int p); + void togglePlayer(Player &plr); void drawPlayer(int p); void update(); diff --git a/src/player.cpp b/src/player.cpp index e4c4b54..1418d91 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -15,7 +15,8 @@ ALuint Player::buffer; float Player::engineVolume = 1.0; Player::Player() - : finished(false) + : joyid(-1), + finished(false) { } @@ -69,6 +70,9 @@ void Player::setTexture(m3dTexture *tex) void Player::setActive(bool a) { active = a; + + if (!active) + joyid = -1; } void Player::setLocal(bool l) @@ -76,10 +80,17 @@ void Player::setLocal(bool l) local = l; } +void Player::setController(SDL_JoystickID id) +{ + joyid = id; +} + Craft &Player::getCraft() { return craft; } bool Player::isActive() const { return active; } bool Player::isLocal() const { return local; } const char *Player::getName() const { return name; } +bool Player::hasController() const { return joyid != -1; } +bool Player::hasController(SDL_JoystickID id) const { return joyid == id; } bool Player::isFinished() const { return finished; } diff --git a/src/player.h b/src/player.h index e3f02de..d1764fc 100644 --- a/src/player.h +++ b/src/player.h @@ -1,6 +1,8 @@ #ifndef _PLAYER_H_ #define _PLAYER_H_ +#include "SDL_gamecontroller.h" + class Player { public: @@ -13,6 +15,8 @@ public: void setTexture(m3dTexture *texture); void setActive(bool active); void setLocal(bool l); + void setController(SDL_JoystickID id); + void unsetController(); void setColor(float r, float g, float b); void setColor(const float *col); @@ -29,6 +33,8 @@ public: bool isActive() const; bool isLocal() const; bool isFinished() const; + bool hasController() const; + bool hasController(SDL_JoystickID id) const; const char *getName() const; void drawHud(const GLint *viewport, int activePlayers, int num); @@ -46,6 +52,8 @@ private: Craft craft; + SDL_JoystickID joyid; + bool active; bool local; bool finished;