2
\$\begingroup\$

I have a 2d game (C++ and SDL) and I want the player object rotate to follow the mouse. The player object and the mouse location are both stored in 2d vectors.

In order to have the player's rotation look nice, I applied this lerp code between the "current" and "future" angle.

This is the function i'm using below, it should be straightforward:

void Vector2D_LerpAngle(const Vector2D& future, const float& dt, Vector2D& current)
{
    float a = 0.0f, b = 0.0f, c=0.0f;

    Vector2D_GetAngleDegrees(future, a);
    Vector2D_GetAngleDegrees(current, b);

    c = (a*t + b * (1.0 - t) - b);

    Vector2D_RotateByDegrees(c, current);
}

This actually works great - until the player rotates past 0 degrees. Then, it suddenly rotates in the opposite direction for almost an entire circle.

The only way I've been able to find to fix this is adding logic to catch the special case of being within 0-360 degrees, but to do that properly I'm going to have to take the velocity of the mouse into account, and that's just going to be a pain. I feel like I'm probably missing something obvious here or else I'm doomed to failure with this particular method.

edit:

It turns out lerping the vectors themselves rather than the angle works. I should have just trusted the math.

void Vector2D_Lerp(const Vector2D& future, const float& t, Vector2D& current)
{
    current = future*t + current*(1.0f - t);
}
\$\endgroup\$
0
\$\begingroup\$

Rather than fiddling with angles, you can use a cross-product to know in which direction you should rotate. Don't be scared by the theory dump : it's actually pretty simple to use!

Let C be current and F be future. They are both 3-dimensional vectors, with z = 0. Then the cross-product P = C×F has the following properties:

  • Px = 0 and Py = 0;
  • Pz = CxFy - CyFx, which is rather easy to compute, but also:
  • Pz = ||C||⋅||F||⋅sin θ, θ being the smaller directed angle from C to F;
  • sin θ and θ have the same sign, unless θ = 180°.

In short: compute (C×F)z, look at its sign:

  • < 0, you need to turn right
  • > 0, you need to turn left
  • = 0, you're either dead centered towards your goal, or facing exactly away.

In the zero case, you can know which situation you're in with the dot product, d = CxFx + CyFy:

  • If d > 0, the vectors face the same direction;
  • If d < 0, the vectors face away from each other;
  • If d = 0, the vectors are orthogonal (but we don't care here).

I hope I managed to be clear enough :)

\$\endgroup\$
  • \$\begingroup\$ That is useful, and it does work, but it doesn't seem to help with my actual problem, which is the actual rotation between one and the other. I can just rotate to a-b and it will follow the mouse precisely but I want there to be a curve so it looks more natural. \$\endgroup\$ – Kenneth Rapp May 30 '16 at 18:54
  • \$\begingroup\$ @KennethRapp that's what it should do. You have to detect whether to rotate clockwise or counter-clockwise, with the formulae above, then apply a small rotation in that direction. \$\endgroup\$ – Quentin May 30 '16 at 21:31
  • \$\begingroup\$ Ok funny story... I found out that if I lerp the vectors themselves instead of the angle, it works just fine. I'm marking your answer as correct, though, because it still is. \$\endgroup\$ – Kenneth Rapp May 30 '16 at 22:05
  • \$\begingroup\$ @KennethRapp that's another solution, but note that you lose the linear motion (i.e. constant speed). It may look better, depending on the situation. \$\endgroup\$ – Quentin May 30 '16 at 22:06
  • \$\begingroup\$ Yes, in this case, constant speed is what I didn't want. Thanks anyway, though. \$\endgroup\$ – Kenneth Rapp May 30 '16 at 22:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.