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

Author Topic: Smooth sf::View movement from point to point  (Read 3656 times)

0 Members and 1 Guest are viewing this topic.

NGM88

  • Full Member
  • ***
  • Posts: 162
    • View Profile
Smooth sf::View movement from point to point
« on: November 19, 2018, 04:15:17 pm »
Hey folks, first a disclaimer: this is a general "gamedev" question, not an "I need help with SFML" question. I hope it's not irritating to the devs to ask this here but I just trust the regular posters here more than other boards and my code in question does use SFML.

The player controls multiple units in my game and the "camera", aka the game world sf::View, moves over to them when a unit is selected. In order to move long distances faster, I tell the view move a portion of the remaining distance between its current position and the destination.

My problem is with the last few frames of movement. I get a lot of "stuttering" which I know stems from the non-integer position of the view; but, if I ceil or floor the position of the view I get an accuracy problem: The view will be off by a large amount (like 8.f) on the x-axis when it reaches the exact desired point on the y-axis or vice versa. This causes a very unnatural jump at the end of movement.

The smoothest movement that I have been able to get is by not flooring/ceiling the floating values and telling the view to stop if the distance remaining in both the x-axis and the y-axis is less than 1.f. My code is posted below.

My questions would be: Would you consider this the ideal way to move the view from one point to another? Is there a way to get smoother movement?

void Camera::setDestination(sf::Vector2f V}
{
        Difference = V - viewWorld->getCenter();

        State = States::Moving;
}
 

void Camera::update()
{
 // if State == Moving

        viewWorld->move(Difference * Speed);
               
        Difference = Destination - viewWorld->getCenter();
               
        if ((std::abs(Difference.x) < 1.f) && (std::abs(Difference.y) < 1.f))
        {
                State = States::Stop;
                viewWorld->setCenter(Destination);
        }
}
 
« Last Edit: November 19, 2018, 04:31:25 pm by NGM88 »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Smooth sf::View movement from point to point
« Reply #1 on: November 20, 2018, 01:15:52 am »
I suppose the question I have is:
Why does rounding the values cause the values to be off by 8?

Is your view the same size as the window (pixel size equals co-ordinate size)? If not, you should consider that the rounding idea is to the nearest pixel, not the nearest co-ordinate. If, for example, a length of 1 in co-ordinate system is equal to 8 pixels, you should multiple the co-ordinate by 8 before rounding and then divide again by 8.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

NGM88

  • Full Member
  • ***
  • Posts: 162
    • View Profile
Re: Smooth sf::View movement from point to point
« Reply #2 on: November 20, 2018, 08:45:02 am »
I suppose the question I have is:
Why does rounding the values cause the values to be off by 8?

Let's say the camera needs to go from sf::Vector2f(-1380, 1260) to sf::Vector2f (-1440, 1290). Here's my output with the code from my first post:

Starting from -1380, 1260 -- Destination is -1440, 1290
Moved to -1387.2, 1263.6
Moved to -1393.54, 1266.77
Moved to -1399.11, 1269.56
Moved to -1404.02, 1272.01
Moved to -1408.34, 1274.17
Moved to -1412.14, 1276.07
Moved to -1415.48, 1277.74
Moved to -1418.42, 1279.21
Moved to -1421.01, 1280.51
Moved to -1423.29, 1281.64
Moved to -1425.3, 1282.65
Moved to -1427.06, 1283.53
Moved to -1428.61, 1284.31
Moved to -1429.98, 1284.99
Moved to -1431.18, 1285.59
Moved to -1432.24, 1286.12
Moved to -1433.17, 1286.59
Moved to -1433.99, 1287
Moved to -1434.71, 1287.36
Moved to -1435.35, 1287.67
Moved to -1435.9, 1287.95
Moved to -1436.4, 1288.2
Moved to -1436.83, 1288.41
Moved to -1437.21, 1288.6
Moved to -1437.54, 1288.77
Moved to -1437.84, 1288.92
Moved to -1438.1, 1289.05
Moved to -1438.33, 1289.16
Moved to -1438.53, 1289.26
Moved to -1438.7, 1289.35
Moved to -1438.86, 1289.43
Moved to -1439, 1289.5
Moved to -1440, 1290
 

Now if I floor the values like this after calling the move function

float x = std::floor(viewWorld->getCenter().x);
float y = std::floor(viewWorld->getCenter().y);
viewWorld->setCenter(x, y);

Then here is the new output:

Starting from -1380, 1260 -- Destination is -1440, 1290
Moved to -1388, 1263
Moved to -1395, 1266
Moved to -1401, 1268
Moved to -1406, 1270
Moved to -1411, 1272
Moved to -1415, 1274
Moved to -1419, 1275
Moved to -1422, 1276
Moved to -1425, 1277
Moved to -1427, 1278
Moved to -1429, 1279
Moved to -1431, 1280
Moved to -1433, 1281
Moved to -1434, 1282
Moved to -1435, 1282
Moved to -1436, 1282
Moved to -1437, 1282
Moved to -1438, 1282
Moved to -1439, 1282
Moved to -1440, 1282
 

As you can see the y-axis if off by 8 where as the x-axis if off by 1.

Is your view the same size as the window (pixel size equals co-ordinate size)? If not, you should consider that the rounding idea is to the nearest pixel, not the nearest co-ordinate. If, for example, a length of 1 in co-ordinate system is equal to 8 pixels, you should multiple the co-ordinate by 8 before rounding and then divide again by 8.

The view is always 1920x1080, but the window can be various other sizes. Unfortunately I don't have the slightest clue how to implement this "round to nearest pixel" method.
« Last Edit: November 20, 2018, 09:00:35 am by NGM88 »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Smooth sf::View movement from point to point
« Reply #3 on: November 22, 2018, 01:38:34 am »
You're immediately setting the view's centre to the rounded values, which, in turn are used for the next rounding?
I would recommend using separate values that track where the view's centre should be logically (using accurate floating points) and then perform the rounding on those values when applying it to the view (by setting the view's centre to rounded values, not just moving it by some value) but don't change the actual tracking values. That way, you're not "getting" the view's centre and have a target value. I mean, rounding 1290 does not give 1282.
This might be the reason that it's not moving to the final position. It certainly seems that by whatever amount you are moving the view is incorrect.

The view is always 1920x1080, but the window can be various other sizes. Unfortunately I don't have the slightest clue how to implement this "round to nearest pixel" method.
The general rule, I suppose, would be multiply by the view size and divide by the pixel size before rounding, remembering to reverse it afterwards by multiplying by the pixel size and diving by the view size. By size here, I mean both width and height but separately.

That, or, for specific positions, you can just convert them:
https://www.sfml-dev.org/tutorials/2.5/graphics-view.php#coordinates-conversions
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

NGM88

  • Full Member
  • ***
  • Posts: 162
    • View Profile
Re: Smooth sf::View movement from point to point
« Reply #4 on: November 22, 2018, 05:39:07 pm »
I would recommend using separate values that track where the view's centre should be logically (using accurate floating points) and then perform the rounding on those values when applying it to the view (by setting the view's centre to rounded values, not just moving it by some value) but don't change the actual tracking values.

I did exactly this and the result is much better. Thanks for the replies.