0

For a game I'm making, I want 3 ships which will all race around the map following a collection of points. It works perfectly fine, except for one point in the map, where the ships decide to rotate almost 360 degrees counter clockwise even though only 10 degrees clockwise should be enough.

The code for calculating the rotation:

vec2 distance = *desiredPosition - position;
float rot = atan2(distance.y, distance.x);
rot = rot * 180.f / PI + 90.f;

if (rot < angle)
{
    angle -= dAngle;
    boat->RotateImage(-dAngle);
}
if (rot > angle)
{
    angle += dAngle;
    boat->RotateImage(dAngle);
}

velocity += vec2(acceleration * cos((angle - 90) * PI / 180.0), acceleration * sin((angle - 90) * PI / 180.0));

How do I ensure it won't rotate in the wrong direction there?


Thanks to Richard Byron (accepted answer below), the problem is fixed. Taking the dot product is better than using degrees.

The final code:

vec2 distance = desiredPosition - position;
normal = vec2(sin((angle - 90) * PI / 180.0), cos((angle - 90) * PI / 180.0) * -1);
float dir = normal.x * distance.x + normal.y * distance.y;

//turn
if (dir > 0)
{
    angle -= dAngle;
    boat->RotateImage(-dAngle);
}
if (dir < 0)
{
    angle += dAngle;
    boat->RotateImage(dAngle);
}

velocity += vec2(acceleration * cos((angle - 90) * PI / 180.0), acceleration * sin((angle - 90) * PI / 180.0));
Wuppy29
  • 347
  • 2
  • 3
  • 13
  • Your problem is going to be around 360 degrees. If your `angle` is 359 but your `rot` is 3 degrees, it should turn right by 4 degrees, not left by 356 degrees. – Cory Kramer Jan 14 '15 at 15:41
  • You need to determine the rotation that would be required to go each direction (CW/CCW) and then pick the smaller one. – Joseph Mansfield Jan 14 '15 at 16:05
  • The other rotation is calculated using: vec2 distance = position - *desiredPosition; right? – Wuppy29 Jan 14 '15 at 16:15

2 Answers2

2

The angle the boat turns should be less than 180 degrees either CW or CCW. If it turns more than 180 degrees in one direction it would have been better to turn the other way.

A more general solution would be calculate the distance vector with respect to the boat's frame of reference.

RonL
  • 41
  • 4
  • How do I calculate the CW direction? Or how would I code your other solution? – Wuppy29 Jan 14 '15 at 16:37
  • Sorry for the late reply. I see from your update you've solved the problem. I was going to say once you have the rotation in one direction calculated, you can easily calculate the other direction (e.g. rot - 360). For the other solution you would have to translate the origin to the boat's position and perform a rotation of the axes to the boat's angle. Perhaps more useful in a 3D situation (when your game uses spaceships instead of boats). Glad you solved the problem, cheers. – RonL Jan 15 '15 at 03:00
  • It actually turns out that the second piece of code still has problems, but only sometimes. At this point I just have no clue why anymore. – Wuppy29 Jan 15 '15 at 10:22
1

There are a couple of problems with your updated code. Firstly, it should be rot2 = 360 - rot1; (rot1 + 360 is exactly the same angle as rot1).

The second issue is that you are not taking into account that 1 and 359 degrees are almost the same angle. So if abs(rot1 - angle) > 180, then you really want to use 360 - abs(rot1 - angle) in that case. Your later comparisons with rot and angle are a problem for the same reason, and you need to handle angle incrementing above 360 and decrementing below 0.

I could write out code for this, but there's actually a much simpler and faster way to do this. If you take the dot product of the vector (desiredPosition - position) and a vector at right angles to the ships current heading, then you can turn based on the sign of that result. If it's not clear how to do this, let me know and I can expand on it in the comments.

Richard Byron
  • 321
  • 2
  • 4
  • Thanks, I know there is some way to calculate it using the dot product and I tried that. However, I couldn't get that to work properly either. What is the right way to calculate it? – Wuppy29 Jan 16 '15 at 07:39
  • The vector at right angle to the heading is: vec2 normal = vec2(heading.y, -heading.x); The dot product is then just float dir = normal.x * distance.x + normal.y * distance.y; You then turn left or right based on the sign of dir – Richard Byron Jan 16 '15 at 15:06
  • If I understand you correctly, the code should be like this: http://pastebin.com/4PNCe1Mq It doesn't work at all though. – Wuppy29 Jan 17 '15 at 09:49
  • The dot product must be between the distance and the heading normal, like this: pastebin.com/ErT8X9RV – Richard Byron Jan 17 '15 at 10:11