Search code examples
c#rotationmonogametweenatan2

Using atan2 for delayed rotation


I have been trying to create a delayed rotation effect with the right analog sticks. The code below takes the angle based on the right analog stick's input and brings the object steadily closer. Due to atan2 being a range of -pi to pi the changing rotation always favors moving through 0 radians as opposed to pi. Is there a way to make the angle travel in the opposite direction?

    private void Angle()
    {
        //Angle to go to
        RotationReference = -(float)(Math.Atan2(YR, XR));

        //Adds on top of rotation to steadily bring it closer
        //to the direction the analog stick is facing
        Rotation += (RotationReference - Rotation) * Seconds *15;
        Console.WriteLine(RotationReference);
    }

Edit:

I tried using InBetween's suggested method which caused the transition between 2pi to 0 a problem. This led me to try something else. I have no idea why it doesn't work.

    private void Angle()
    {
        //Angle to go to
        RotationReference = -(float)(CorrectedAtan2(YR, XR));

        //Adds on top of rotation to steadily bring it closer
        //to the direction the analog stick is facing
        if (Math.Abs(RotationReference - Rotation) > Math.PI)
            Rotation += ((float)(RotationReference + Math.PI * 2) - Rotation) * Seconds * 15;
        else Rotation += (RotationReference - Rotation) * Seconds *15;
        Console.WriteLine(RotationReference);
    }

    public static double CorrectedAtan2(double y, double x)
    {
        var angle = Math.Atan2(y, x);
        return angle < 0 ? angle + 2 * Math.PI: angle;
    }

The idea behind this is that if you need to travel more than 180 degrees you will make the angle to travel to greater than 360 degrees. This should eliminate the need for reversing the direction.


Solution

  • After some experimentation I managed to make it work. Thanks InBetween for the CorrectedAtan2 method. The for loop is used to go through all of the instances where you would need to add pi to avoid the jarring transition.

        private float Angle(float y, float x)
        {
            //Angle to go to
            RotationReference = -(float)(CorrectedAtan2(y, x));
    
            for (int i = 0; i < 60; i++)
            {
                if (Math.Abs(RotationReference - Rotation) > Math.PI)
                    RotationReference = -(float)(CorrectedAtan2(y, x) +
                        (Math.PI * 2 * i));
            }
            //Adds on top of rotation to steadily bring it closer
            //to the direction the analog stick is facing
            return Rotation += (RotationReference - Rotation) * Seconds * 15;
        }
    
        public static double CorrectedAtan2(double y, double x)
        {
            var angle = Math.Atan2(y, x);
            return angle < 0 ? angle + 2 * Math.PI: angle;
        }