Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: What happened to the Rotation of a Sprite?  (Read 3317 times)

0 Members and 1 Guest are viewing this topic.

MickeyKnox

  • Jr. Member
  • **
  • Posts: 50
    • View Profile
What happened to the Rotation of a Sprite?
« on: June 12, 2011, 07:34:45 pm »
After upgrading to SFML 2.0, i can't get my animating function working.

What it does is to move a Sprite to it's destination (Course) by turning first,
until the Sprite is rotated towards its destination, and then moving straight.

The turning doesn't work any more. Either it rotates, or it moves in the
wrong direction (depends on the condition, det is checked for; either > or <).

Code: [Select]
void
normalize (sf::Vector2f& v)
{
    v /= (float) sqrt (pow (v.x, 2) + pow (v.y, 2));
}

float
distance_pow_2 (const sf::Vector2f& v1, const sf::Vector2f& v2)
{
    return (float) pow (v2.x - v1.x, 2) + pow (v2.y - v1.y, 2);
}

void
Unit::Animate (float TimeSpan)
{
    if (Position == Course) return;

    float angle = atan2 (Course.y - Position.y, Course.x - Position.x) * 180.f / PI + 90.f;
    //float angle = atan2 (Position.x - Course.x, Position.y - Course.y) * 180.f / PI;
    if (angle < 0) angle += 360.f;

    //std::cout << "angle: " << angle << std::endl;

    float distance =  Speed * TimeSpan * 3.6;

    Rotation = Sprite.GetRotation ();
    //std::cout << "Rotation: " << Rotation << std::endl;

    if (abs (abs (angle) - abs (Rotation)) < 0.1) // move straight
    {
        if (pow (distance, 2) > distance_pow_2 (Course, Position))
        {
            Position = Course;
        }
        else
        {
            sf::Vector2f direction = Course - Position;
            normalize (direction);
            direction *= distance;
            Position += direction;
        }
    }
    else // turn
    {
        float turn = asin (distance / (2.f * Probs->TurningRadius)) * 180.f / PI;

        if (abs (abs (Rotation) - abs (angle)) < abs (turn))
        {
            Rotation = angle;
        }
        else
        {
            float x = sin (Rotation * PI / 180.f);
            float y = cos (Rotation * PI / 180.f);
            sf::Vector2f front (x, y);
            front += Position;

            // Sarros' Rule
            float det = front.x * Course.y + Position.x * front.y + Course.x * Position.y -
                Position.y * front.x - front.y * Course.x - Course.y * Position.x;

            Rotation += (det < 0) ? -turn : turn;
        }

        float x = sin (Rotation * PI / 180.f);
        float y = cos (Rotation * PI / 180.f);
        sf::Vector2f front (x, y);
        normalize (front);
        front *= distance;
        Position -= front;
    }
}


Position and Course are vector2f's, i hope the rest is clear.

After i got it working with SFML 1.6, i was hoping, i'll never have to fiddle with this code again.
I hate trigonometry...

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
What happened to the Rotation of a Sprite?
« Reply #1 on: June 12, 2011, 08:42:05 pm »
Rotations are inverted on Y axis (to be consistent with the coordinates system which is top to bottom).
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
What happened to the Rotation of a Sprite?
« Reply #2 on: June 12, 2011, 09:14:32 pm »
See here for a more detailed discussion about the topic.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

MickeyKnox

  • Jr. Member
  • **
  • Posts: 50
    • View Profile
What happened to the Rotation of a Sprite?
« Reply #3 on: June 12, 2011, 10:13:06 pm »
Quote
Rotations are inverted on Y axis


yeah, i figured that. But my animator still behaves weird...

Quote
See here for a more detailed discussion about the topic.


Has this issue already been addressed in the current version?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
What happened to the Rotation of a Sprite?
« Reply #4 on: June 12, 2011, 10:19:05 pm »
Quote
Has this issue already been addressed in the current version?

Yes, that's why rotations are now inverted ;)
Laurent Gomila - SFML developer

MickeyKnox

  • Jr. Member
  • **
  • Posts: 50
    • View Profile
What happened to the Rotation of a Sprite?
« Reply #5 on: June 18, 2011, 02:55:18 pm »
After some time fiddeling with my animation function, it does again
what i want it to do. However, I'm not really happy with it. I know, this is
some ugly piece of code, but i give my best to document what is going on.

Code: [Select]
// this function is called every frame in my game, to determine the new
// position and rotation of the unit.
void
Unit::Animate (float TimeSpan)
{
    // Position is the current position of the unit, Course is its destination.
    // Both are vector2f's.
    if (Position == Course) return;

    // The angle between the position and the course
    float angle = atan2 (Course.y - Position.y, Course.x - Position.x) * 180.f / PI + 90.f;
    if (angle < 0) angle += 360.f;

    // The distance, the unit should move towards its destination
    float distance =  Speed * TimeSpan * 3.6;

    // Get the actual Rotation (the Rotation will be set to the Sprite, before it is drawn)
    Rotation = Sprite.GetRotation ();

    // If the unit is oriented towards its destination, move straight
    if (abs (abs (angle) - abs (Rotation)) < 0.1)
    {
        // If the unit is almost at its destination, meaning closer then
        // distance away, just put it directly to its destination
        if (pow (distance, 2) > distance_pow_2 (Course, Position))
        {
            Position = Course;
        }
        // Else, move towards its destination
        else
        {
            sf::Vector2f direction = Course - Position;
            normalize (direction);
            direction *= distance;
            Position += direction;
        }
    }
    // Else, update the Rotation and move in that direction
    else
    {
        // turn is the amount in degrees, by which the unit should turn.
        // The formula is non-trivial, and i can't explain it without making
        // a drawing. Please just believe, that this is doing the right thing.
        float turn = asin (distance / (2.f * Probs->TurningRadius)) * 180.f / PI;

        // Similar to above, if the unit is almost oriented towards its
        // destination, just set the angle.
        if (abs (abs (Rotation) - abs (angle)) < abs (turn))
        {
            Rotation = angle;
        }
        // Else, rotate the unit. First, the direction in which the unit should
        // turn must be computed, it should choose the smaller turning circle.
        // This is also non-trivial, i didn't even
        // bothered to understand the proof, why this is doing the right thing,
        // but it works.
        else
        {
            float rot = 360.f - Rotation;
            float x = sin (rot * PI / 180.f);
            float y = cos (rot * PI / 180.f);
            sf::Vector2f front (x, y);
            front += Position;

            // Sarros' Rule
            float det = front.x * Course.y + Position.x * front.y + Course.x * Position.y -
                Position.y * front.x - front.y * Course.x - Course.y * Position.x;

            // Finally, update the Rotation
            Rotation += (det > 0) ? -turn : turn;
        }

        // Now move by distance along the new Rotation
        float rot = 360.f - Rotation;

        float x = sin (rot * PI / 180.f);
        float y = cos (rot * PI / 180.f);
        sf::Vector2f front (x, y);
        normalize (front);
        front *= distance;
        Position -= front;
    }
}


Ok, so this code works, i can see the unit moving on my screen as i want it
to. However, there are several things in the code, that don't make sense to
me, they are only there, because it works that way.

I have the strong feeling, that SFML and the standard C++ trigonometry
functions have a different understanding of angles. And SFML 2.0 made it
even worse!

The first thing to notice is that C++ functions deal with angles in radians,
whereas SFML Rotations use degrees. This can be dealt with fairly easy
with all these ugly PI / 180.f resp. 180.f / PI.

But now to the things that don't make sense to me.

Up in the beginning, when i compute 'angle', i have to add 90 degrees,
to make it match with the SFML Rotation. Why?

In the turning block, before i can feed the Rotation to the C++
trigonometry functions, i have to invert the Rotation.
(float rot = 360.f - Rotation;) Why?

In the end, when updating the Position, i have to use -=, whereas when
moving straight, i use +=. Why?

I'm open to the possibility, that i'm doing something retarded here.
I that case, i hope someone will explain it to me.

 

anything