Search code examples
c#rotationangleraylib

Rotating a square to point at a Vector2 gets completely messed up at 0 degrees


This is the code that rotates the boat to follow the line. A joint is just a Vector2 on the line. To the left is 0 degrees. And as you can see, when the boat is going from 0 to 360 or vice versa degrees, it glitches out.

float LookAt(Vector2 joint)
{
     float deltaY = rect.y - joint.Y; // Calculate Delta y

     float deltaX = joint.X - rect.x; // Calculate delta x

     float angle = (float)(Math.Atan2(deltaY, deltaX) * 180.0 / Math.PI) + 90; // Find angle

     float amountToRotate = angle - rotation;

     amountToRotate *= 0.05f;

     Console.WriteLine($"Rotation: {rotation} Angle: {angle} Amount: {amountToRotate}");

     return rotation + amountToRotate;
 }

I'm using an amountToRotate variable because I want the rotation to be a little smooth (doesn't show well on the GIF).

https://gyazo.com/cd907763665ac41a2c8f8e5d246ab292

Any help is much appreciated.

(I'm also doing this in Raylib if that makes any difference).


Solution

  • Because atan2() returns values between -PI and +PI or between -180 and +180 degrees. So, if your boat is looking at something like 170 deg and the next joint is at 179 deg, then your amountToRotate is +9 deg, which is fine. But, if your boat is looking at 180 degs and your the joint is at -180 deg, your amountToRotate is suddenly -360 deg (-180 - 180), which is facing right towards the positive x-axis. The you take 5% off of amountToRotate and add it to your current rotation (180 - 360*0.05 = 162) which means, that the boat is turning away from the node.

    As a quick solution, you could convert the angle to full 360 degrees:

    angle = (angle + 360) % 360;
    

    But you will still get problems in the direction of the positive x-axis. The better solution would be to calculate the angle between two vectors and invert it:

    angleTowardsV2FromV1 = -(Math.atan2(v1.y, v1.x) - Math.atan2(v2.y, v2.x))
    

    in your case this would look something like:

    angle = (-(Math.atan2(Math.sin(rotation*Math.PI/180), Math.cos(rotation*Math.PI/180)) - Math.atan2(deltaY, deltaX)))*180/Math.PI
    

    And also, if you only take 5% of your angle, the rotation will never get there. I think, it would much wiser to clamp the angle to +-5deg:

    const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
    angle = clamp(angle, -5, +5);
    

    And the just return:

    return rotation + angle;
    

    I hope this helps.