Files
devilutionX/SourceX/controls/controller_motion.cpp
T
Gleb Mazovetskiy a2e821d241 Game controller support
Initial game controller support.

Actions are based on the Switch branch but the controller code itself is
implemented differently, allowing for easy remapping and minimizing
changes to the Source/ directory.

Many subtle and not so subtle controller bugs have been fixed
in this implementation, including:

1. Smoother & more responsive movement with the joysticks.
2. Consistent controls for all the menus in the game (stores, quest log,
etc).
3. Cursor appearance / disappearance at appropriate times.

Low-level controls are abstracted and 3 SDL interfaces are supported:
game controller, joystick, and keyboard. See SourceX/controls/ for more
details on this.

Wishlist for the future:

1. Primary button and use button should attack continously.
   This is hard as it requires checking the cooldowns / attack speed.
2. Quick spell menu navigation is very buggy. It is also buggy in the
   switch branch. I haven't had a change to investigate.
2019-11-06 02:13:07 +01:00

92 lines
2.4 KiB
C++

#include "controls/controller_motion.h"
#include "controls/devices/game_controller.h"
namespace dvl {
namespace {
void ScaleJoystickAxes(float *x, float *y, float deadzone)
{
//radial and scaled dead_zone
//http://www.third-helix.com/2013/04/12/doing-thumbstick-dead-zones-right.html
//input values go from -32767.0...+32767.0, output values are from -1.0 to 1.0;
if (deadzone == 0) {
return;
}
if (deadzone >= 1.0) {
*x = 0;
*y = 0;
return;
}
const float maximum = 32767.0f;
float analog_x = *x;
float analog_y = *y;
float dead_zone = deadzone * maximum;
float magnitude = sqrtf(analog_x * analog_x + analog_y * analog_y);
if (magnitude >= dead_zone) {
// find scaled axis values with magnitudes between zero and maximum
float scalingFactor = 1.0 / magnitude * (magnitude - dead_zone) / (maximum - dead_zone);
analog_x = (analog_x * scalingFactor);
analog_y = (analog_y * scalingFactor);
// clamp to ensure results will never exceed the max_axis value
float clamping_factor = 1.0f;
float abs_analog_x = fabs(analog_x);
float abs_analog_y = fabs(analog_y);
if (abs_analog_x > 1.0 || abs_analog_y > 1.0) {
if (abs_analog_x > abs_analog_y) {
clamping_factor = 1 / abs_analog_x;
} else {
clamping_factor = 1 / abs_analog_y;
}
}
*x = (clamping_factor * analog_x);
*y = (clamping_factor * analog_y);
} else {
*x = 0;
*y = 0;
}
}
} // namespace
float leftStickX, leftStickY, rightStickX, rightStickY;
float leftStickXUnscaled, leftStickYUnscaled, rightStickXUnscaled, rightStickYUnscaled;
bool leftStickNeedsScaling, rightStickNeedsScaling;
void ScaleJoysticks()
{
constexpr float rightDeadzone = 0.07;
constexpr float leftDeadzone = 0.07;
if (leftStickNeedsScaling) {
leftStickX = leftStickXUnscaled;
leftStickY = leftStickYUnscaled;
ScaleJoystickAxes(&leftStickX, &leftStickY, leftDeadzone);
leftStickNeedsScaling = false;
}
if (rightStickNeedsScaling) {
rightStickX = rightStickXUnscaled;
rightStickY = rightStickYUnscaled;
ScaleJoystickAxes(&rightStickX, &rightStickY, rightDeadzone);
rightStickNeedsScaling = false;
}
}
// Updates motion state for mouse and joystick sticks.
bool ProcessControllerMotion(const SDL_Event &event)
{
#ifndef USE_SDL1
if (ProcessGameControllerAxisMotion(event))
return true;
#endif
return false;
}
} // namespace dvl