# How to get smooth circular input from a thumbstick in XNA?

I have a mouse-based game that I'm trying to get to work nicely with the Xbox gamepad. My major issue is trying to get the cursor to move smoothly like it does with the mouse. Using GamePadDeadZone.IndependentAxes makes it hard to move at slight angles, so I switched to GamePadDeadZone.Circular.

It turns out that the values that I'm getting from the controller are diamond shaped instead of being circular. Pushing all the way up gives me (0,1), and pushing right gives me (1,0), but pushing to the top-right gives me (.7,.7).

This leads to a quite noticeable slowdown when traveling at angles. My game requires the player to move carefully at times and quickly at others, but it's near impossible because you'll move faster or slower depending on the angle of the thumbstick. How can I get truly circular data back?

• Have you tried normalizing the values? Throw the values in a Vector2 and use the Normalize method. – William Mariager Jan 25 '12 at 0:25
• That removes all sensitivity from the sticks though which would be annoying if you need to do minor corrections. – ClassicThunder Jan 25 '12 at 0:44

What you describe actually sounds it is giving true circular data. If it's circular and the maximum radius is 1, then pushing top-right at exactly a 45-degree angle should give you (0.7071, 0.7071). (That number is sqrt(0.5)).

If you're getting a slowdown when traveling diagonally, then I presume something else is going on. How are you using the controller values to move the player? If you use it as a 2D vector to set the player's velocity, you should get the same speed in all directions. Note that if you had (1, 1) for the vector the player would actually move 40% faster when going diagonally.

If what you want is for the vector to come out as (1,1) - which might be the right choice for your game; I wouldn't know - then I think you can do this by calculating the radius and then scaling the vector to make the biggest component equal to the radius, like:

r = sqrt(x*x + y*y);
maxComp = max(abs(x), abs(y));
if (maxComp > 0) {
x *= r / maxComp;
y *= r / maxComp;
}


This should retain all sensitivity but map the circle to a square, so the output will be within [-1, 1] on each axis and you'll be able to get to all four corners of the box.

Lastly, note that a common way to improve sensitivity is to square the length of the joystick vector, which makes small deflections smaller, while leaving bigger deflections alone. You could do this by removing the sqrt on the equation for r above.

• Holy crap, you're totally right! All the funky stuff happening is because of stuff I added before I knew about GamePadDeadZone.Circular. Removed all that and it worked like a charm. I feel so dumb. >_< – Califer Jan 25 '12 at 5:05

First, .7,.7 is circular shaped, not dimaond shaped. Do the math of how long a vector is form 0,0 to sqrt(.5),sqrt(.5) which is your .7,.7. It is exactly 1.0.

Next, some Xbox 360 controllers return absolute values of 1,1 in the corners, such as my MadCatz, and some controllers return .7,.7, such as the official Microsoft controllers that come with the system. You must take this into account, or else 3rd party controllers will allow your character to move faster in your game, effectively becoming a hack.

Thirdly, also be sure to read my "Multidirectional XNA Games Control Tip" article, http://xona.com/2010/05/03.html, in case you are coding for smooth motion 360 degrees. If you don't take this into account, you'll lock at 12,3,6,9 directions. Good for some games, bad for most multi-directional shmups. I've even seen pro XBLA games make this brutal mistake, and far too many XBLIG games do. EDIT : I mention this to explain both the proper usage of GamePadDeadZone.Circular as well as solve an all too common problem.

• @Califer, you are welcome. As for GamePadDeadZone.Circular, I noticed you were already using it but it seemed you were either guessing at it or did not understand it, but my article listed above shows what it's actual purpose is, so I had to mention it. – Xonatron Jan 26 '12 at 18:30
x += .3(1 - |x - y|)