Accurate sprite rotation with mouse movement

I am using the current mouse position to aim the player sprite, but I am not getting the best results.

It will often by off by a noticeable amount, or even a complete ~180 off if I go from one side, through the player, to the other side.

boolean mouseMoved(int screenX, int screenY) {
mouseX = screenX;mouseY = screenY;
rot = MathUtils.radiansToDegrees * MathUtils.atan2((float)mouseY - (float)player.y, (float)mouseX - (float)player.x);
if (rot < 0) rot += 360;
player.setRot(rot);
}


Update 1:

When I am at 90/270 it seems to pickup the angle fine. But for 0/180, the angle is off depending on how far away my cursor is to a certain point (not the player's point).

Update 2:

Added in semi-fix, but I'm still having the same exact problem

Update 3:

I was mistaken the semi-fix wasn't actually a fix. I fixed it for real, though. The problem was that libgdx has (0,0) at the bottom left, but the InputProcessor has (0,0) at the top left. What I had to do was adjust the mouse position so that it's (0,0) was the bottom left. I did this by

mouseX = screenX;
mouseY = Game.HEIGHT - screen y;


This will give the player coordinates & mouse coordinates the same origin, and then the formula will work.

• 1) Did you make sure player.setRot() take a degrees argument instead of a radian one? 2) You can remove the (float) castings, they will not change anything in your case. 3) How did the rot == 360 semi-fixes the problem? Have you made more test cases with different values? Aug 13, 2014 at 1:48
• You should put Game.HEIGHT instead of WIDTH if you want the vertical size of the screen... Aug 13, 2014 at 17:07
• Totally right. I must have just derped when translating. Aug 13, 2014 at 17:08
• If you answered your own question, feel free to write an answer to your post and mark it as the accepted answer. Aug 13, 2014 at 17:10
• I posted my answer, hopefully it's enough info to help someone in the same spot. Aug 13, 2014 at 17:22

Try multiplying the y value with -1.

And make sure to convert the mouse and playercoordinates to the world coordinates.

I had this exact problem yesterday. It has to do with wrong conversion - think about the two different coordinate-systems (Viewport- and World-coordinates)

• It's fine to suggest things that you're not sure will work or not. However, you should explain what problem your suggestion solves and why you think your suggestion will solve that problem. Aug 12, 2014 at 20:43
• Sorry I'm on the phone and my answer was fairly short. Extended the answer. Aug 12, 2014 at 20:45
• My word and viewport are the exact same size. Aug 12, 2014 at 20:50

Try using different math techniques for the rotation: Instead of degrees, try using Quaternions. It's the most used rotation technique for 3D objects in professional engines, because degrees don't work as well in 3D.

There's more on Wikipedia and I found some Libgdx code.

I have more materials, but I can't include them due to my low reputation, but you can find lots on Google.

• I'm doing all this in 2d. I'm rotating a polygon, and from what I have seen there isn't an option to use a quaternion Aug 12, 2014 at 20:52

First, inverse the player position and the mouse position. This way, you will have the real angle from the player to the mouse, and not the opposite.

Second, atan2 takes the y difference as the first argument, and the x difference as the second. That is probably why your code looks like it fails.

Your code should look like this with the 2 corrections I mentioned:

boolean mouseMoved(int screenX, int screenY) {
mouseX = screenX;
mouseY = screenY;
// Inverted mouse and player position as well as X and Y axis
float angle = (float)Math.toDegrees(Math.atan2(mouseY - player.y, mouseX - player.x));
players.setRot(angle);
}

• @Brandon Have you applied any of the fixes I posted? If yes, please update your question. And for the bounty thing, please do not. Aug 12, 2014 at 22:47
• Ok I will not do that. Yes I did put your fix in, but I'm having the same problem where the degrees are off at the 0 degree and 180 degree (see update 1). Aug 12, 2014 at 23:01

The problem was that libgdx has the origin (0,0) in the bottom left corner, but the mouse movement from the InputProcessor has (0,0) in the top left. What I had to do was adjust the mouse y position so that its (0,0) was the bottom left. I did this with:

mouseX = screenX;
mouseY = Game.HEIGHT - screenY;


This will give the player coordinates and mouse coordinates the same origin, and then the formula will work.

Here is the entire working code snippet:

boolean mouseMoved(int screenX, int screenY) {
mouseX = screenX;
mouseY = Game.HEIGHT - screenY;
rot = MathUtils.radiansToDegrees * MathUtils.atan2(mouseY - player.y, mouseX - player.x);
player.setRot(rot);
}