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);
}
}
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.