Add SDL_GameController support

This commit is contained in:
Hannes Mann 2016-06-15 16:51:05 +02:00
parent 1ed79727cb
commit c277fb918d
4 changed files with 100 additions and 9 deletions

View file

@ -22,6 +22,7 @@ namespace openrayman
{
m_input.stick_x = m_input.stick_y = m_input.buttons = m_input.commands = 0;
poll_keyboard();
poll_game_controller();
return m_input;
}
@ -32,8 +33,6 @@ namespace openrayman
// Keyboard
// This is not 100% accurate to the original PC version because
// the N64 version is not the same as the PC version
// TODO: rebindable keyboard controls
// and controller...
// Control stick
// This simulates a slower walk done by the control stick
@ -41,14 +40,23 @@ namespace openrayman
// TODO: Is half (64) accurate?!?!
int walk_strength = keyboard_state[SDL_SCANCODE_LSHIFT] ? 64 : 127;
int new_stick_x = m_input.stick_x;
int new_stick_y = m_input.stick_y;
if(keyboard_state[SDL_SCANCODE_LEFT])
m_input.stick_x -= walk_strength;
new_stick_x -= walk_strength;
if(keyboard_state[SDL_SCANCODE_RIGHT])
m_input.stick_x += walk_strength;
new_stick_x += walk_strength;
if(keyboard_state[SDL_SCANCODE_UP])
m_input.stick_y -= walk_strength;
new_stick_y -= walk_strength;
if(keyboard_state[SDL_SCANCODE_DOWN])
m_input.stick_y += walk_strength;
new_stick_y += walk_strength;
new_stick_x = std::min(127, std::max(-127, new_stick_x));
new_stick_y = std::min(127, std::max(-127, new_stick_y));
m_input.stick_x = new_stick_x;
m_input.stick_y = new_stick_y;
// Front buttons
if(keyboard_state[SDL_SCANCODE_SPACE])
@ -82,4 +90,63 @@ namespace openrayman
if(keyboard_state[SDL_SCANCODE_F11])
m_input.commands |= input_command::toggle_fullscreen;
}
void standalone_input_provider::poll_game_controller()
{
// Game controller
// Again, not 100% accurate to the original PC version because
// the N64 version is not the same as the PC version and the original game
// was not meant to be played with Xbox controllers and frankly, the original
// layout is shit and doesn't work most of the time (dinput)
for(const std::pair<int, SDL_GameController*>& pair : m_game_controllers)
{
SDL_GameController* controller = pair.second;
// Control stick
std::int16_t stick_x = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) / 258;
std::int16_t stick_y = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) / 258;
int new_stick_x = m_input.stick_x;
int new_stick_y = m_input.stick_y;
new_stick_x += stick_x;
new_stick_y += stick_y;
new_stick_x = std::min(127, std::max(-127, new_stick_x));
new_stick_y = std::min(127, std::max(-127, new_stick_y));
m_input.stick_x = new_stick_x;
m_input.stick_y = new_stick_y;
// Front buttons
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A))
m_input.buttons |= input_button::a;
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X))
m_input.buttons |= input_button::b;
// Triggers
if(SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > 20000 ||
SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER))
m_input.buttons |= input_button::z;
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_Y))
m_input.buttons |= input_button::l;
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_B))
m_input.buttons |= input_button::r;
// Start button
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START))
m_input.buttons |= input_button::start;
// C buttons
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT))
m_input.commands |= input_button::cbtn_left;
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT))
m_input.commands |= input_button::cbtn_right;
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP))
m_input.commands |= input_button::cbtn_up;
if(SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN))
m_input.commands |= input_button::cbtn_down;
}
}
}

View file

@ -5,6 +5,7 @@
#include <input/input_provider.h>
#include <SDL2/SDL.h>
#include <string>
#include <unordered_map>
namespace openrayman
{
@ -12,6 +13,7 @@ namespace openrayman
// Sources are GLFW and libgcadapter.
class standalone_input_provider : public input_provider
{
friend class sdl_window;
public:
standalone_input_provider(SDL_Window* window);
~standalone_input_provider();
@ -20,8 +22,10 @@ public:
const input_state& poll() override;
private:
void poll_keyboard();
void poll_game_controller();
input_state m_input;
SDL_Window* m_window;
std::unordered_map<int, SDL_GameController*> m_game_controllers;
};
}

View file

@ -105,6 +105,26 @@ namespace openrayman
case SDL_QUIT:
m_wants_close = true;
break;
case SDL_CONTROLLERDEVICEADDED:
{
SDL_GameController* ctrl = SDL_GameControllerOpen(event.cdevice.which);
if(ctrl)
{
SDL_Joystick* joy = SDL_GameControllerGetJoystick(ctrl);
int id = SDL_JoystickInstanceID(joy);
m_input_provider.m_game_controllers[id] = ctrl;
}
break;
}
case SDL_CONTROLLERDEVICEREMOVED:
if(m_input_provider.m_game_controllers.count(event.cdevice.which) > 0)
{
SDL_GameControllerClose(m_input_provider.m_game_controllers[event.cdevice.which]);
m_input_provider.m_game_controllers.erase(event.cdevice.which);
}
break;
}
}
}