Single axis deadzone

The single axis deadzone is hard to get wrong. Your analog trigger, throttle lever, or other single-axis analog device, should give you a value between 0 and 1, or in the case of some devices that can move both ways, a value between -1 and 1, with a resting position at 0.

Here the solution is almost brutally simple. Easy mode is to just reject values below some threshold

Here we’ve simply mapped the values from 0 to 0.2 so that they equal 0.

There’s a small problem though, as we slowly push the trigger down, we’ll suddenly hit the threshold and jump to 0.2

This might be okay, depending on the situation, but it might feel janky when precision is needed in the lower values.

What we need to to is map the value of 0.2 to 0 while continuing to have 1 map to 1. To do this we need a little bit of subtraction and division.

Replacing our x with

(x-0.2)/(1–0.2) will do this nicely. (I’ll let the programmer nerds optimise this by storing values and converting divisions to multiplications)

Now we have a nice line that goes through all the values between 0 and 1, with a safe deadzone on the input.

Two axis deadzone

Joysticks and thumbsticks output their data as a pair of numbers, x and y, with numbers ranging from -1 to 1. The “easy” solution is to just apply single axis deadzones to both of these, and call it a day, right?

Well, no… (Although, this is what Unity does, it also doesn’t map the lower values). If we do this, then we run into a problem. Imagine we’re pushing the stick fully forwards to make the character run, and then we want to turn a bit to the right. If we’ve deadzoned both axes independently, then we’ll have to move the stick quite a bit to the right before it picks up. We fall into this weird situation where if we move the stick in a circle, we get a weird “stickyness” in the up, down, left and right positions.

Let’s go back to the intro to remind ourselves why we’re doing the whole deadzone thing again:

Between two “high” values, this is rarely a problem […]. Where this breaks down though, is at the zero point.

Running forwards full-barrel is hardly the “zero point”, is it? And running full-barrel slightly to the right should be taken into account because:

As long as pushing more increases the effect and pushing less decreases, the actual values being read don’t matter.

Moving the stick to the right of the fully forwards position counts as pushing more or less, we want to see a change in effect.

We need to take both the x and y values together. What we’re trying to filter out is the slight wobble when the stick is allowed to stay in its idle position, but any value outside of that needs to be taken into account. What we need is to know the distance of the stick from its zero point.

Remember the Pythagorean theorem? For those of you who don’t, this is quite simple maths, we don’t need to know why it works here, we just need the formula, it’s a really useful (arguably the most useful) formula in game development, so try to memorise it.

On a right angle triangle, the Pythagorean theorem states that the square of the hypotenuse (the long side, opposite the right angle, we’re calling it c), is equal to the sum of the squares of the two other sides (a and b).

We can write that: a²+b²=c²

What we want is a formula to find c so we flip the equation and take the square roots, which gives us:

c=√(a²+b²)

How does this help us? Well if we say that x=a and b=y, then we’ll find that the number c is the distance from zero. In mathematical terms, we can say that c is the magnitude of (x, y)

We’re going to use this value c to filter out unwanted inputs, and to avoid the “jolt” on the threshold, we can also use it to scale x and y without changing the “shape” of the input.

Step one, if c is lower than our threshold (we’ve used 0.2 in the single axis case, so let’s keep using it here), then just use (0, 0) instead of (x, y).

At this point we’ve successfully made a functioning deadzone, but if you use this, there will be a noticeable jank when you cross the 0.2 line.

Step two involves a little math again, but it’s super, super simple. We want to scale the values x and y. First we normalise (x, y), which means we change its size to have a magnitude of 1. We do this by dividing x and y by c, so we get: nx = x/c and ny = y/c

Then we modify c the same way we did in the single axis case:

c’ = (c-0.2)/(1–0.2)

Multiply our new (nx, ny) by c’: (nx×c’, ny×c’)

And send these values to the game…

Phew, that felt like a lot of math. If you’re not sure how to turn this all into code or you’re afraid you’ll get it wrong, you can use my JavaScript implementation, it’s general enough that you shouldn’t have too much trouble converting it to whatever language you use.