3
var diffx = (this.destination.x - pos.x), px = diffx / dist;
var diffy = (this.destination.y - pos.y), py = diffy / dist;
var angle = Math.atan2(diffy, diffx) - rot.z;

rot.set(0, 0, rot.z + angle / 24);

An object points towards my mouse cursor. I use the above code to calculate the angle in radians and "animate" the angle over a few frames. However, when the angle variable turns from positive to negative (at PI radians), it turns clockwise all the way to the new cursor position (as seen in red). However, my desired path is to go straight to the new angle (green arrow).

enter image description here

EDIT:

This is what I came up with, seems to work. Could I improve?

            if(atan - this.lastAtan < -Math.PI)
                atan += Math.PI * 2;
            else if(atan - this.lastAtan > Math.PI)
                atan -= Math.PI * 2;
            this.lastAtan = atan;

            var zrot = rot.z + (atan * 12 * Game.dt);
            rot.set(0, 0, zrot % (Math.PI * 2));
John
  • 816
  • 5
  • 17

1 Answers1

3

You have to take into account that the output of atan2 is only ever in the range -pi to +pi. If the difference between the output of atan2 and your previous angle is greater than pi, then you know that some wraparound occurred, and you have to correct for it by adding/subtracting 2*pi.

Jack Whitham
  • 609
  • 4
  • 9
  • Works well for one rotation, but does same thing the second time I turn. I'm assuming I have to keep adding/subtracting 2pi for however many rotations I've done. – John Apr 30 '15 at 01:15
  • 1
    You can possibly use the modulo operator to avoid repeated addition/subtraction - http://stackoverflow.com/questions/16505559/how-can-i-use-modulo-operator-in-javascript . – Jack Whitham Apr 30 '15 at 09:54
  • Thanks, I got something working. I added it to the OP, could I simplify it? – John May 01 '15 at 05:55
  • The modulo operator may be redundant in this case. I think you have a good solution without it. Assigning `this.lastAtan = atan` *after* the `if` statements is the thing that really makes it work. – Jack Whitham May 01 '15 at 09:12
  • I do need it, it's complicated to explain. Without it, the object would unwind itself again. `if(atan - this.lastAtan < -Math.PI)` is only true for one rotation, because I only ever do `atan += Math.PI * 2;` once. Before my current solution I tried it with an internal variable named `rotations` and recorded how many times it crossed side, and added 2pi per rotation. However, my current method doesn't require an internal state. – John May 01 '15 at 10:03