Torque/Analog Input

From TDN

Contents

Analog Input in Marble Blast Ultra

Introduction

Taking input from analog controlers can be a cumbersome thing for players to come to grips with, or it can make movement silky smooth. It's all in the code. In this (hopefully brief) article, I am going to describe the way I did the controls for Marble Blast Xbox, and Marble Blast Ultra on the Xbox360.






A Note on Analog Input

Firstly, for all the code after this bit, I am going to be treating input as a floating point value between -1.0 and 1.0. The value from the analog sensor does not come in like this. It will come in a 16-bit signed integer format. Positive stick value indicates the stick being moved up, vs down, or right vs left. To convert this, do the following:

// analogInput is the data from the gamepad analog sensor.
F32 fInput = (F32)-analogInput/(F32)S16_MAX;

Deadzones

There is a "deadzone" on all analog controls, where you have to ignore input in a certain range, because it is most likely noise. For gamepads it is around -0.26f to 0.26f, and any input in that deadzone you have to ignore. So the obvious solution is this:

stickValue = ( fInput >= deadZoneBegin && fInput <= deadZoneEnd ? 0.f : fInput );

The Problem With The Obvious Solution

If you look at this, what you see is that it ignores any input values between -0.26f and 0.26f (deadZoneBegin and deadZoneEnd, respectivly). Now there is a problem to this, you will find, if you test it in a game with various input speeds, you will go from not moving, to moving fast in no time. This is because input values into the game will now read between -1.f to -0.26f and 0.26f to 1.f. No other input values are sent as an input event. What you need to do is generate a range of values that is uninterupted.

// First, cull out the dead zone areas
if( fInput >= deadZoneBegin && fInput <= deadZoneEnd ) 
   stickValue = 0.f;
else
{
   if( value > 0 )
      stickValue = ( fInput - deadZoneBegin )  / ( 1.f - deadZoneBegin );
   else
      stickValue = ( fInput + deadZoneBegin ) / ( 1.f - deadZoneBegin );
}

Lets Really Make This Good

What this will do is re-scale the input value to be between -1.f and1.f. This will yield a smooth transition between dead zone area, and valid input area. Now you may be thinking, "Ah good, that is as good as it gets. Now it's smooth like buttah!" but you are wrong! This works for some input, but if you want to really make the game controls a blast (an...Ultra Blast?) you need to modify the input acceleration and fit it to a non-linear function. The function you chose for your game is going to depend on your specific input needs. For example, in Marble Blast, I wanted to give the user very fine control at the low-end, when they were pushing the stick only a little, then give movement much more impact when they were pushing the stick near the max range. You may want to do it the opposite way, in which case the function I used won't be what you want to use.

// Taking stickValue from the last code block
// (because we still need to do what that code block did BEFORE DOING THIS)
stickValue = ( stickValue < 0.f ? -1.f : 1.f ) * mPow( mFabs( stickValue ), CONST_E );

In Marble Blast, CONST_E is defined as:

2.7182818284590452353602874f

The graph of x^e, between 0.0 and 1.0 looks like this:
Image:Xtothee.png

The axies of the graph, X is the input, Y is the output. This should actually be able to give you a kind of visual "feel" for how the control stick will respond to input, and graphing it is how I easly rejected some early functions I was thinking of. In the end, the simplicity of x^e was just what was needed.

Conclusion

That's all for my little wandering on input functions. Hopefully it will help out some games that are looking to add a little extra oomph into their movement.