In the last section, we’d been forced to make the least-worst decision in terms of getting the most out of our input ranges by capping off the maximum throw of the stick. It looks and (mostly) feels like it’s used to define a direction and and a magnitude, as opposed to two separate axes clamped off by a circle (which is closer to the truth).
The hardware represents neither of these paradigms perfectly, so we’ve made the choice to go with what a user perceives that the input allows. The X & Y axis information available can absolutely give us an approximation of this mental model of the stick’s input, but in cleaning up the maximum and minimum siginals (the upper and lower DeadZones), we’ve created another problem: one of continuity.
The springs are providing a gradually increasing force on our thumbs as they slowly push outwards, but the player character speeds in our demos, when leaving or entering the deadzone, are not gradual at all – they’re sudden and unexpected.
If our actual force vs. travel graph on the stick matched this (which would feel like frictionless thumb movement within the within the deadzone, then a palpable “start” of the spring resistance at the deadzone’s edge), then this model would be right on. But the spring force is always felt, to different degrees, where ever it’s placed, from full force at the extremities to zero at the center: a continuum of reactive force.
Compare this to the feel within the game, where the change in speed almost comes as a shock. There’s no instant feedback from the haptics of the controller itself to signify that our minute movement should change anything at all (like some kind of a “notch” in the mechanism). We only get feedback via the long route – through the game and back through visual feedback to tell us that we’re actually moving now, even though the stick has been deflected off the center for quite some time.
The physical affordances of the stick suggest a continuum, but the output gives us a sudden jump, and then a gradual increase of speed, as we increase deflection. This creates a kind of “kinaesthetic dissonance” between controls and in game action. We need the jump from “dead” to “not dead” to be gradual in order to better marry the two feels.
So here’s what we do: Code: Re-normalize the range. We’re re-mapping the magnitude of the true input such that at full input deflection, we get full output deflection, but at the deadzone’s beginning, we get a zero output, rather than stepping up suddenly.
float renormalizedRange = Mathf.Clamp01(input.magnitude - deadZone)/(1.0f - deadZone)); Vector2 CircularDeadZone = input.normalized * renormalizedRange;
Hooray! Starting to feel considerably less like complete thumb-junk! Note that the magnitude readings on the left only occur between 0.5 (our deadzone value) and 1, while the outputs on the right go from zero all the way to one.
We’ve cropped off the noisey extremities through dead zoning (lower and upper bounds), and now we’ve re-mapped the output to the remaining useful input range we received.
But there’s still more we can do!