How do I find the shortest distance around a circle from one degree value to another, simply by adding or subtracting rotational velocity?

75 Views Asked by At

I am trying to create a movement system for a 2D spaceship game using only the arrow keys. So essentially I have a 2d vector and I want to use that to set a rotation for my spaceship. If the ship starts with an angle of 0, and then I press the up arrow the ship should rotate from 0 to 90 degrees or pi/2 from 2pi based on a rotation velocity. This is the code I have that does this.

    private void updateRotation()
    {
        if (Direction.X < 0)
        {
            setRotationValue(MathHelper.ToRadians(180));
        }
        if( Direction.X > 0)
        {
            if(MathHelper.ToDegrees(rotation) < 180)
            {
                setRotationValue(MathHelper.ToRadians(0));
            }
            else
            {
                setRotationValue(MathHelper.ToRadians(360));
            }
            
        }
        if(Direction.Y < 0)
        {
            setRotationValue(MathHelper.ToRadians(270));
        }
        if(Direction.Y > 0)
        {
            setRotationValue(MathHelper.ToRadians(90));
        }
        
    }

    private void setRotationValue(float target)
    {
        if (target > rotation)
        {
            rotation += MathHelper.ToRadians(rotationVelocity);
        }
        if (target < rotation)
        {
            rotation -= MathHelper.ToRadians(rotationVelocity);

        }
    }

<

However, my problem arises in a situation where the ship is say facing 45 degrees and I want to rotate to 270 degrees. Well if I press the down key the target rotation is greater then the current rotation so it goes from 45 to 270. This is not the quickest path, as it would be much faster to go from 45 back to 0, then start at 360 and go down to 270. I'm not sure the best way to implement this in code, or if my approach is the right way to do this. I have had a long conversation with chat GPT, which did not give me a solid answer. Any help or direction on how to solve this problem would be much appreciated, especially if this problem is even possible or if I need to look into something like Euler angles or quaternions.

SECOND ATTEMPT TO EXPLAIN: -----------------------------------------

I have an arrow with a starting rotation value of 0 degrees or 2pi, so it is parallel to the x axis. If I tell it to go up, I want it to slowly increment its rotation by some number (I called it rotation velocity before) until its rotation value reaches 90 degrees or pi/2. I have achieved this already with my code.

Now Lets say I have told it to go up but I let go of a key when its at 45 degrees or pi/4. Now I tell the arrow to change its rotation value untill the arrow is facing straight down and is parallel with the Y axis (270 degrees or 3pi/2). (My Problem): With the code previous, target rotation value is 270 or 3pi/2, and current rotation value is 45 or pi/4, so it is going to increment the rotation value untill the target value is reached, even though it would be faster to decrement the rotation value back to 0, then set it to 360 or 2pi and continue decrementing to reach 270 or 3pi/2.

So not sure how to determine that that is the faster route mathmatically.

I described values in radians and degrees throughout this as its easier to wrap my head around. By telling the arrow to rotate I mean pressing keys. For example the key mappings are D or left = 0 degrees or 2pi W or up = 90 degrees or pi/2 A or right = 180 degrees or pi S or down = 270 degrees or 3pi/2 While the user is holding a key, the arrow in the example, (or the spaceship in the game I'm trying to make) increments or decrements its rotation value until its rotation value is equal to one of the 4 targets defined in the key mappings above. If the ship is at 90 degrees and the user holds D, the rotation would slowly increment until it reaches 0 degrees or the user lets go of the key.

2

There are 2 best solutions below

1
On

I don't fully understand what you want your arrow keys to do, or what you mean by "rotation velocity" in your context, but let me try to restate your goal mathematically:

You have a starting angle $S$, and a desired ending angle $E$, and you want to find an angle $D$, with $-180 \lt D \le +180$, so that $$ E = S + D \mod 360$$

(If that wouldn't solve your problem, please explain further. Also, I'll keep things in degrees, as that's how you've written your question.)

I'll go through the solution in multiple steps, to make it easier to understand, but you certainly can combine equations together in your code if you wish.

First, let's set $$D_0 = E -S$$ And then we'll convert units to "full rotations" $$ d_0 = D_0/360$$

Now, set $$ n = \text{closest_integer_to}(d_0)$$

I'd normally expect this to correspond to a function named round(), but not all computer languages have a "native" round() function that behaves right, especially when handling negative numbers. You should find one where round(-1.7) equals -2, not -1. And when it comes to rounding, there can be a lot of discussion of what will happen with half-integral values, like $3.5$, but we don't care about that here - rounding them either up or down will work for us.

Next, set $$d = d_0 -n$$

Notice that we've modified the amount we rotate by an integral number of full rotations, which doesn't make a difference with angles.

Finally $$ D = 360 * d$$ converting back to degrees to give us the final desired answer.

One nice thing about this is it doesn't matter what range of values your $S$ and $E$ angles are in. If you had been slowly incrementing the value of $S$ and it was currently at, say, $5735$ degrees, you could still use $270$ as your $E$ value and the computed $D$ value would still be between $-180$ and $180$. And of course you can change the two occurences of "$360$" to "$2\pi$" if your angles are kept as radians.

(I gotta confess that I haven't done any 'testing' of this with actual values; it's just what makes sense mathematically. So you might want to run a few test cases after you code it up to make sure I don't have a bug!)

0
On

Throughout the following, I am assuming that all angles are expressed in degrees and that counterclockwise is the positive direction.

Here is my interpretation of the problem: We have two angles of $\theta$ and $\phi$ expressed in the range from $0$ to $360$, and we want to move along the unit circle from $\theta$ to $\phi$ in the shortest direction, which could be either clockwise or counterclockwise.

Start by computing $\delta = \phi - \theta$. If $\delta > 180$, subtract $360$ from $\delta$. If $\delta < -180$, add $360$ to $\delta$. You now have $-180 \le \delta \le 180$. If $\delta > 0$, move counterclockwise $\delta$ degrees; if $\delta < 0$, move clockwise $-\delta$ degrees.

The key is to realize that adding or subtracting $360$ degrees from an angle results in the same angle under a different "name". By the way, similar computations crop up often in real world problems involving terrestrial longitude.