1
\$\begingroup\$

All right, so I'm testing two box objects. One is standing fixed in a position and another at the beginning of the program goes to the first one. And at the end the latter should stand completely over the first (so the center of both is equal).

Here's my method in the Object class:

Old code

void Object::moveTo(Point _p) { // _p is always the center of the other object we want to go to

    // adjust speed, don't worry it's not important here, I guess
    if (current_speed == 0)
        current_speed = speed/16;
    else if (current_speed >= speed)
        current_speed = speed;
    else
        current_speed *= 2;

    // we want to calculate the new center of the
    // our object (the one that run this method)
    Point center;
    // distance(x) calculate the distance between the center point of the object and
    // the x point passed
    if (distance(_p) <= current_speed) {
        // we don't want shaking things!
        center = Point(_p.x, _p.y);
    } else {
        // move diagonally
        center.x = getCenter().x + current_speed*std::cos(angle(_p)); // angle calculates the angle between the center of the object and the _p point
        center.y = getCenter().y + current_speed*std::sin(angle(_p));
    }
    // since we draw sprites by the top left corner we need to convert
    // the center point to the correct top left point
    center = toPosition(center);
    sprite.setPosition(center);
}

New code

Notice that the origin of the sprite is set to be in the center so setPosition will correctly set the center and that getCenter() returns sprite.getPosition() which is the center point.

void Object::moveTo(Point _p) {
    Point center;
    //std::cout << distance(_p) << std::endl;
    if (distance(_p) <= speed) {
        center = Point(_p.x, _p.y);
    } else {
        center.x = getCenter().x + speed*std::cos(angle(_p));
        center.y = getCenter().y + speed*std::sin(angle(_p));
    }
    sprite.setPosition(center);
}

This is what happens: http://youtu.be/Ngra3FXFe0A.

The distance keeps going from 15.xxx to 16.xxx and I don't know why.

Testing surprise

  • Doing distance(_p) <= 10 instead doesn't make it shake. With 9, 8... or minor it shakes.
  • Defining a minor speed the object gets nearer the correct position before start shaking.
  • Setting the white cube to follow the player (yellow sprite) it moves like a jagger: http://youtu.be/9FjRfHHprEQ
  • Here's a recent video: the 3 little squares points (its the specific top left corner) to: blue = box center, red = player center, green = top left corner of the box. As you can see they are correctly calculated (this test was made with speed of 1, while the others were made with a greater speed): http://youtu.be/iFAWGssk7NI

Distance function:

float Object::distance(Point _p) {
    return sqrt((pow((getCenter().x - _p.x), 2) + pow((getCenter().y - _p.y), 2)));
}

Angle function

float Object::angle(Point _p) {
    //  (180 / PI = 57.3065)
    return 57.3065f * atan2(getCenter().y - _p.y, getCenter().x - _p.x);
}

Why is that?

\$\endgroup\$
8
  • \$\begingroup\$ Can you paste the source of the distance function? \$\endgroup\$
    – r2d2rigo
    Commented Jul 30, 2012 at 9:33
  • \$\begingroup\$ @r2d2rigo, added \$\endgroup\$
    – Shoe
    Commented Jul 30, 2012 at 9:34
  • \$\begingroup\$ What's the underlying data type in the Point class? What about speed and current_speed? Do you convert floating point values back to int at some time, such as rendering time? \$\endgroup\$ Commented Jul 30, 2012 at 16:27
  • \$\begingroup\$ @SamHocevar The underlying data type for Point is sf::Vector2f which is a vector of 2 floats. I do not ever convert any value into another data type in my entire game (not even a simple cast) and no conversion in made implicitly by the compiler either (or a warning would pop up). \$\endgroup\$
    – Shoe
    Commented Jul 30, 2012 at 16:35
  • \$\begingroup\$ How is getCenter() implemented? \$\endgroup\$
    – Kylotan
    Commented Jul 30, 2012 at 17:33

3 Answers 3

1
\$\begingroup\$

It's clear that the simple 'new' code posted doesn't have a significant problem - the angle calculation looks correct, and as soon as the object would get within range, the position will be set to _p.x, _p.y, which is exactly where it needs to be. The only reason this would ever jitter is one of the following:

  1. current_speed hits zero when distance(_p) is non-zero (perhaps due to floating point error), meaning the sprite moves a full amount again - this seems the most likely problem in the 'old' code, but you don't show how you calculate current_speed, and it's not even in the 'new' code;
  2. distance(_p) changes even when _p and the sprite's position are constant;
  3. _p is not constant, and something is periodically changing it, even when the object appears to be still;
  4. the following sprite's position is not constant, despite being set to equal _p - perhaps something else moves the sprite;

One way you can reduce the jitter is to remove the "move or don't move" test and instead scale the movement amount proportional to the distance to the target. You don't need an angle at all - just calculate the movement vector (your current argument to atan2() in angle()) and if the length of the vector is more than your speed, scale it down to that size. Otherwise, leave it as it is. Then add that vector to your sprite's position to apply the movement. It's impossible to overshoot that way because the length of the movement is never bigger than the distance to the target.

But don't do this until you find the problem in your code that is causing the issue, otherwise you'll just be hiding a bug rather than fixing it!

\$\endgroup\$
7
  • \$\begingroup\$ 1. Current speed was not necessary at all, that's why I removed it in the new code. The old and the new code behave the same way, so that was not the problem. 2. It does not, I run some test printing out the distance and it was correctly calculated. If the speed was 1 it was correctly scaled of one each time, but I don't know why, at 15 or 16 it just stopped. 3. As you can see in the last video, when the sprite stay still the little square is pointing at its center and stay still. 4. I'll check this one, but in the first test the only thing that was moving the sprite was that function. \$\endgroup\$
    – Shoe
    Commented Jul 31, 2012 at 6:18
  • \$\begingroup\$ Also we still don't explain how is does that "turn around" in some points when the player is moving, or why it stop some other times. \$\endgroup\$
    – Shoe
    Commented Jul 31, 2012 at 6:23
  • \$\begingroup\$ Would it helper if I post the entire code? \$\endgroup\$
    – Shoe
    Commented Jul 31, 2012 at 6:26
  • \$\begingroup\$ For distance, what do you mean it "just stopped"? I have one more suggestion - what is the type of the speed variable? If it's an int, that could cause problems. But beyond that, I have no suggestions - this is something you'll need to debug yourself. Reduce the number of variables involved as far as you can and log everything each frame, verifying the values of _p, distance, angle, etc. \$\endgroup\$
    – Kylotan
    Commented Jul 31, 2012 at 9:44
  • \$\begingroup\$ I meant that at 15, 16 it keeps going from 15 to 15 and viceversa. And yes, obviously the speed is an int. How could that cause a problem? \$\endgroup\$
    – Shoe
    Commented Jul 31, 2012 at 10:31
0
\$\begingroup\$

In this part:

    center.x = getCenter().x + speed*std::cos(angle(_p)); // angle calculates the angle between the center of the object and the _p point
    center.y = getCenter().y + speed*std::sin(angle(_p));

I think you want current_speed instead of speed.

\$\endgroup\$
1
  • \$\begingroup\$ It obliviously doesn't solve the shaking problem. \$\endgroup\$
    – Shoe
    Commented Jul 30, 2012 at 16:02
0
\$\begingroup\$

Do you know guys what the problem was? This: 57.3065f. This makes the angle() function returns degrees. And this was bad because std::sin and std::cos expects radians to be passed.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .