3
\$\begingroup\$

I'm messing about with a knockoff PS3 controller and SDL2 on windows, and noticed that despite the circular restriction, when I position the stick as close as I can to an extreme diagonal, I am reading a max value for displacement on the X and Y axis. Now as a newbie, I would not expect this as obviously in this position the stick is some way from being as far displaced in either axis as it could be. So it seems that the region for min and max readings is a square whose limits are well within the full circular range of movement of the stick, and anything outside this region is deadspace.

I guess different controllers might have different exact sizes for deadzones, but in general, is it the case that all analog controllers are going to exhibit this general behaviour?

\$\endgroup\$
2
  • \$\begingroup\$ That's funny, I asked myself the same question just yesterday when trying to calibrate a Xbox One controller clone. It didn't quite reach max values in the diagonals, but was significantly outside of the circle defined by the two axes. I assumed it was some sort of nonlinear 2D mapping to get more out of the value range along diagonals, but now I'm curious to actually know. \$\endgroup\$ – Quentin Mar 8 at 13:47
  • \$\begingroup\$ The PS3 one I have definitely seems to map to a square that's quite a lot smaller then the largest square that could be contained within the circular restriction. Because of this, if I want to use the analog stick to control a player's velocity, I need to apply a transformation, otherwise my character will be able to travel faster along diagonals than laterally. \$\endgroup\$ – Tom Davies Mar 8 at 14:15
1
\$\begingroup\$

Yes, this is a common issue with analog stick inputs, on most if not all gamepad hardware.

We typically apply a circular clamping function a little like this:

Vector2 ClampAnalogInput(Vector2 input, float innerDeadzone, float outerDeadzone) {

    float magnitude = input.magnitude;

    float scale = (magnitude - innerDeadZone)/(outerDeadZone - innerDeadZone);

    return input * Clamp(scale, 0, 1)/magnitude;
}

This preserves the direction of the input, while scaling the magnitude of the output to lie between 0 and 1, so diagonals have the same maximum magnitude as the cardinal directions.

The two tuning parameters represent...

  • the size of the inner dead zone: input inside this radius will be mapped to 0, clamping out drift and noise

  • the outer dead zone: input at or beyond this radius will be mapped to 1 - shrink this if you find your device isn't able to hit the full 1.0 magnitude in a particular direction

Unfortunately all gamepad models are a little different out of the box, and their parameters change in different ways as they age, so it's hard to pin down one set of tuning values that works ideally for all devices. The best advice we can give is to experiment with a range of new and old controllers, or expose these parameters as tunable options for your players to be able to support their pad's idiosyncrasies.

Exposing these tuning options can also help make your game more accessible for players using custom input devices, with reduced range of motion making it hard to move the stick all the way to the limit, or tremors that make hard to hold the stick steady.

\$\endgroup\$
1
  • \$\begingroup\$ Great. I actually ended up with something very similar myself - basically a function mapping points on a unit square onto a unit circle. I guess this is portable as well, should there exist a controller whose analog stick readings are genuinely contrained to a circle. \$\endgroup\$ – Tom Davies Mar 8 at 15:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.