Jump to content
  • Advertisement
Sign in to follow this  
Tom 'Rossy' Rosbotham

How do I calculate if I should be adding or subtracting rotation?

This topic is 2287 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

(I'm an XNA/C# Newbie).

I currently have an Asteroids-style character that is controlled by the mouse.

However, I'm having an issue when my ship's movement would have it turn across the "west" line.

mvlufm.jpg

This is my current code for rotating:


if (destAngle - rotation <= 0)
{
rotation -= movingRotationSpeed;
}
else
{
rotation += movingRotationSpeed;
}


However, an issue arises when the mouse crosses over the "west" line (with respect to the sprite). The destAngle changes from -3.140 to +3.140 (radians/PI). If I'm going clockwise at the time, the ship will then do a massive anti-clockwise movement (and vice verse).

What computation should I be doing to determine if the ship should move clockwise or anti-clockwise given I have its current angle and the destination angle?

Here is my entire code segment for that method:


MouseState mouseState = Mouse.GetState();
Vector2 mouseLoc = new Vector2(mouseState.X, mouseState.Y);

Vector2 direction = position - mouseLoc;
destAngle = (float)(Math.Atan2(-direction.Y, -direction.X));

if (mouseState.LeftButton == ButtonState.Pressed)
{
Console.WriteLine(rotation + " + " + destAngle);

if (destAngle - rotation <= 0)
{
rotation -= movingRotationSpeed;
}
else
{
rotation += movingRotationSpeed;
}

if (position.X == mouseState.X && position.Y == mouseState.Y)
{ }
else
{
//The ship always moves "forward".
position.X += speed * (float)(Math.Cos(rotation));
position.Y += speed * (float)(Math.Sin(rotation));
}
}

Share this post


Link to post
Share on other sites
Advertisement
If what I think you mean is correct, you cannot have a naturally smooth rotation transition if you only use velocity (= rotation). You need to implement acceleration in order to obtain smooth transitions. Basically instead of deriving your velocity from the mouse position, you derive your acceleration from the mouse position, add the acceleration to the velocity, and finally add the velocity to the resulting position. This will give you more or less smooth changes of direction depending on how strong you make the acceleration.

Also you do not need angles in your code here. If you look closely you are doing an inverse tangent of your mouse coordinates to obtain the rotation angle, and then proceed to undo that operation by reconstructing the rotation vector with sin and cos. You could simply normalize the rotation vector and use that directly. You will need to do that to implement acceleration as it is much nicer with vectors than with angles.

Share this post


Link to post
Share on other sites
What I would do is something along the lines of the following:

targetRotation;
otherTargetRotation = (targetRotation < 0) ? targetRotation + 2*PI : targetRotation - 2*PI;
if(abs(targetRotation - rotation) > abs(otherTargetRotation - rotation)
{
//go one way
} else
{
//go the other
}


Note: This is totally untested, but sounds good in my head.

Share this post


Link to post
Share on other sites
otherTargetRotation = (targetRotation < 0) ? targetRotation + 2*PI : targetRotation - 2*PI;


I'm not sure I understand this syntax? But that aside.

I've disabled forward motion for the purposes of testing without it going off the screen.

Your solution has seemingly worsened the problem. Whenever the destination is above the X-axis, it turns to face left and then stops rotating. Now given that it is impossible for it to not rotate (there's no if condition where it doesn't rotate): that means that it reaches an argument where both statements are true, and the ship is turning up then down again instantly.

Share this post


Link to post
Share on other sites
The question mark colon is a ternary operator for simplifying an if else block used for assignment.

http://en.wikipedia.org/wiki/Ternary_operation

Share this post


Link to post
Share on other sites
What that line says is if the targetRotation is less than 0 set the otherTargetRotation to targetRotation + 2PI; otherwise, set it to targetRotation-2PI.

Here is complete working code with the missing bits filled in. This has been tested and works.


#include <iostream>
#include <cmath>
using namespace std;
#define PI 3.14159265
int main()
{
cout << "Current Rotation?\n";
float currentRotation;
cin >> currentRotation;
cout << "Target Rotation?\n";
float targetRotation;
cin >> targetRotation;
while(currentRotation != targetRotation) //rotate
{
int direction = targetRotation - currentRotation > 0 ? 1 : -1;
float otherTargetRotation = targetRotation < 0 ? targetRotation + 2*PI : targetRotation - 2*PI;
cout << "Target: " << targetRotation << endl;
cout << "Other: " << otherTargetRotation << endl;
char c;
cin >> c;
if(abs(targetRotation - currentRotation) > abs(otherTargetRotation - currentRotation))
{
direction *= -1;
}
currentRotation+=.1*(float)direction;
if(currentRotation > PI) currentRotation-= 2*PI;
if(currentRotation < PI*-1.0f) currentRotation+=2*PI;
if(abs(targetRotation-currentRotation) < 0.1) currentRotation = targetRotation;
cout << "Current Rotation: " << currentRotation << endl;
}
}


You will obviously want to set your own thresh hold and velocity, and remove the input/output statements.

EDIT: Some of my code was cut-off in my copy-paste. It should now be fixed.

Share this post


Link to post
Share on other sites
Zael's method is written in C++ rather than C#. He uses cin and cout to set the variables for the rotation.




cout << "Current Rotation?\n";
float currentRotation;
cin >> currentRotation;
cout << "Target Rotation?\n";
float targetRotation;
cin >> targetRotation;

>> sets the value entered on the command line into the variable that follows the >>. Similarly bout << prints whatever follows into a command prompt.

You will want to remove all the cin and cout anyways and set the variables according to your game. The important part to understand is



while(currentRotation != targetRotation) //rotate
{
int direction = targetRotation - currentRotation > 0 ? 1 : -1;
float otherTargetRotation = targetRotation < 0 ? targetRotation + 2*PI : targetRotation - 2*PI;
if(abs(targetRotation - currentRotation) > abs(otherTargetRotation - currentRotation))
{
direction *= -1;
}
currentRotation+=.1*(float)direction;
if(currentRotation > PI) currentRotation-= 2*PI;
if(currentRotation < PI*-1.0f) currentRotation+=2*PI;
if(abs(targetRotation-currentRotation) < 0.1) currentRotation = targetRotation;
}

as that is the part that does the actual rotation. What do you not understand in this part?

Share this post


Link to post
Share on other sites

[background=rgb(250, 251, 252)]Sorry, I was editing that post as you wrote. I managed to successfully translate the code, after Googling all the syntax I didn't understand. But thank you for also clarifying.[/background]


___

If I use the while loop as provided in the code, the ship will instantly turn to face the cursor with no "turning" actually present. It just always looks at the cursor. However, while using the while-loop, the rotation itself is perfect.

However, changing the while to an if-loop gives me the "turning" I'm looking for. However, the issue I had with my own code is exactly the same in this code. Upon attempting to cross the west-axis, the ship attempts to do a 359-degree spin in the opposite direction. With forward motion enabled (rather than a stationary sprite), the ship just ~~~~~~~~ in a straight line.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!