Monday, April 30, 2007

GamePad Dead Zone functionality

The last couple of nights I've been working on the dead zone functionality for the GamePad class in MonoXna, which was an interesting excursion off into formula's and equations I haven't been exposed to for many years.

I read an post by Shawn Hargreaves, which gave me a good start on understanding the MSXNA implementation.  I've now implemented the basic functionality of the two algorithms, IndependentAxis and Circular.

I used Shawn's formula for the IndependentAxis deadzone calculation and here is a plot of this:

Independent Axis - Plot X Independent Axis - Plot XY
IndependentAxisPlotX4  IndependentAxisPlotXY1 

I ended up using a variation of Shawn's formula for the IndependentAxis and using a bit of trig, ended up with the following for the Circular implementation:

/// <summary>
/// As per http://blogs.msdn.com/shawnhar/archive/2007/03/28/gamepads-suck.aspx
/// Both <paramref name="x"/> and <paramref name="y"/> parameters assumed to be between -1.0 and 1.0
/// </summary>
static Vector2 CircularAxisDeadZone(float x, float y)
{
    float dist = (float)Math.Max(Math.Sqrt(x * x + y * y), EPSILON);
    float deadZone = Math.Max(dist - DEADZONE, 0)/(MAX_DIST - DEADZONE)/dist;
    return new Vector2(x*deadZone, y*deadZone);
}

The MSDN documentation states that the Circular algorithm uses the combined position of both joystick axes to make the deadzone calculation.  So,

  1. We calculate the distance from the centre, and if zero, returning EPSILON, so we never divide by zero.
  2. If we're in the DEADZONE (=0.2f), we'll clamp to 0, otherwise we'll create a weighting factor for the deadzone calculation
  3. return a Vector2 with the new x,y values

Here is a plot of our IndependentAxis calculation:

Circular - Plot XY
CircularPlotXY1 

No comments: