Floats subtraction and comparisons

Pages: 123
I know the problem is in the if() statement and the math there. When I get rid of the if() statement and just have the top image follow the bottom with just

 
ImageTop.setPosition(ImageTop.getGlobalBounds().left - 	m_SpeedScalesMovingRow * dt.asSeconds(), ImageTop.getGlobalBounds().top);


It works fine and smooth. So it is definitely loss of precision in the math somewhere.
Why L21 0.1f (float) rather than 0.1 (double)? double * float gives a type double so the cast on L21 wouldn't be needed and the answer would be more exact.
If you want xxxx.yyyyyy (10 significant digits) then consider:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <iomanip>

int main() {
	const auto xf { 9876123456 / 1000000.0f };    // float

	std::cout << std::setprecision(6) << std::fixed << xf << '\n';

	const auto xd { 9876123456 / 1000000.0 };    // double

	std::cout << std::setprecision(6) << std::fixed << xd << '\n';
}


which displays:


9876.124023
9876.123456


Note the inaccuracy for float display. You need double. Also note that if you are receiving a type float from a value or function and expect this to 10 significant digits of precision then this can't be guaranteed. This will only happen with a double. So even if you're casting the received float to a double, then there could still be issues due to the float type of the received value.
Last edited on
Is this the only place where you update ImageTop's position?

I guess you're using SFML? I'm no expert on it, unfortunately.

Perhaps you want to check so that ImageTop.getGlobalBounds().left is the same as ImageTop.getPosition().x.

I have a feeling that m_SpeedScalesMovingRow * dt.asSeconds() could lead to problems if dt happens to be too large. It could definitely lead to moving a little bit too far. Just to rule out that this is not the issue you might want to set it to the intended position directly.
Last edited on
SubZeroWins wrote:
When I get rid of the if() statement and just have the top image follow the bottom ...

Follow? Doesn't removing the if() mean it will always move left at constant speed regardless of how ImageBottom moves?
Last edited on
seeplus, I saw that too and was saving that as a last trial for tomorrow but I tried it today after reading your post and no go, same deal.


Peter, yes it is SFML. And no it is not the only place but I deleted all the other code to get to the basics and now I am working on this modified and deleted code to try and squeeze the problem.


ImageTop.getGlobalBounds().left is the same as ImageTop.getPosition().x


I am doing scaling and will be doing transformations on the image also down the road, so one needs to use ImageTop.getGlobalBounds().left to get the scaled or transformed versions of the coordinates and ImageTop.getPosition().x will not give the proper coordinates.


Follow? Doesn't removing the if() mean it will always move left at constant speed regardless of how ImageBottom moves?


Yes, I removed the if() to rule out the math and it moves beautifully as it should without any glitches and skips at a constant rate of (1200 pixels * dt.asSeconds()).

I also tried to slow it down to 50 pixels movement and it still misbehaves but takes a lot longer to catch them because it is moving so slowly and takes longer for me to see them.

So what I think is happening is that the pixel moves to the left is not the same for the images with changes to dt and so the check <= does not occasionally fall through for a brief moment in time and it lags briefly behind and gives this jitter appearance.

Maybe I will try to set the ImageTop.left() always based on the ImageBottom.left() +/- the offset and not based on it's own left position. This way it can never really be out of sync and not relying on a separate dt....it will always be relying on the dt for the ImageBottom.

I will try that after some sleep and see how that goes.
SubZeroWins wrote:
I am doing scaling and will be doing transformations on the image also down the road, so one needs to use ImageTop.getGlobalBounds().left to get the scaled or transformed versions of the coordinates and ImageTop.getPosition().x will not give the proper coordinates.

Okay, but isn't setPosition also operating on the non-transformed coordinates?

For example, Let's say
ImageTop.getGlobalBounds().left is equal to ImageTop.getPosition().x + 10
and
ImageTop.getGlobalBounds().top is equal to ImageTop.getPosition().y - 5
and then you called
ImageTop.setPosition(ImageTop.getGlobalBounds().left - 10, ImageTop.getGlobalBounds().top);
which looks like it would move left, right?
But it wouldn't because it's the same as
ImageTop.setPosition(ImageTop.getPosition().x, ImageTop.getPosition().y - 5);
which means it would move on the y-axis but stand still on the x-axis,
or am I wrong?

SubZeroWins wrote:
it still misbehaves but takes a lot longer to catch them because it is moving so slowly and takes longer for me to see them.

I still don't understand exactly what goes wrong. The box moves up and down? It moves too much sometimes and sometimes too little? It goes back and forth? Or is it some kind of transformation that goes wrong? Is it only off by one pixel or is it more?

If you use Windows you might want to try putting the DPI scale settings to 100% (I think it is 125% by default). I've seen it cause ugly artefacts in some programs. This wouldn't really be a solution but could perhaps give some clue.
Last edited on
I read that it is not what you expected. I did not understand correctly your request, but just for sharing - for float precision I use a single template returning a string according to a float which I want to round using only a few digits...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <sstream>
#include <cmath>

template<class T> 
inline std::string float_precision(const T value, const int n = 2) 
{ 
    std::ostringstream out; 
    out.precision(n); 
    out << std::fixed << value; 
    return out.str(); 
}

int main() 
{
    const long double pi = acos(-1); // PI
    std::cout << float_precision(pi, 10) << std::endl;
    std::cout << float_precision(pi, 20) << std::endl;
    std::cout << float_precision(pi, 40) << std::endl;
    return 0;
}


3.1415926536
3.14159265358979311600
3.1415926535897931159979634685441851615906
SubZeroWins wrote:
So what I think is happening is that the pixel moves to the left is not the same for the images with changes to dt and so the check <= does not occasionally fall through for a brief moment in time and it lags briefly behind and gives this jitter appearance.

As I said earlier, if dt is too large (perhaps because your computer was busy running some other program for a while) it is possible that you move too far. Because you check and then you move without taking the distance into account.

Even if dt is small what might be happening, especially if m_SpeedScalesMovingRow is large, is that you move and then you have to wait for ImageBottom to catch up, and then you move again and have to wait for ImageBottom to catch up again, and so on. This might not necessarily look wrong but it would look like ImageTop was updated at a lower frequency and moved in larger steps compared to ImageBottom.

You might want to at least limit the position so that you don't set it further to the left than it should be in relation to ImageBottom. I think that would fix the above issues.

The above assumes you want to have a max speed for ImageTop so that if ImageBottom is far away (to the left) from ImageTop it should take some time for ImageTop to catch up. But if that is not the case and instead you want ImageTop to always follow the position of ImageBottom exactly then you should not be using dt at all and just calculate the exact position based on ImageBottom and update the position every frame.
Last edited on
The way it works is that there is:
ImageTop.getGlobalBounds()
ImageTop.getLocalBounds()

The global reports coordinates to any changes to the image, such as rotations and transformations. The local reports the original image. They are both in there for convenience because often they are used in relational calculations to one another. You can adjust image size/rotation all you want and if at the end you want to just make it 1/2 of the original image, then you got it!

For instance for a scaling of the image the .left() & .top() remains the same values for the global & local, but the width & height changes.

There is only 1 setPosition for the image, which is THE IMAGE, and you are going to want to use getGlobalBounds() for consistency so you can get the proper height & width if need be. But if you are not scaling/rotating, then one can use getPosition consistently.


For the issue that I am experiencing it is never in the top position, always in the .left (X-axis). As if the dt for the ImageTop on occasions was above average and made the x-axis move faster than the check and then the check catches up again and continues moving the top image again. It is quick and quirky and like a fast skip in place on the x-axis.
Last edited on
SubZeroWins wrote:
There is only 1 setPosition for the image, which is THE IMAGE, and you are going to want to use getGlobalBounds() for consistency so you can get the proper height & width if need be. But if you are not scaling/rotating, then one can use getPosition consistently.

If you rotate or change the origin and then keep calling
 
ImageTop.setPosition(ImageTop.getGlobalBounds().left, ImageTop.getGlobalBounds().top);
repeatedly then ImageTop will start to wander away.

I pieced together some code to verify that it worked this way, and it did. I admit I used SFML 2.4 (which is not the latest version) and sf::RectangleShape (instead of sf::Sprite) but I'm pretty sure it works the same.

SubZeroWins wrote:
As if the dt for the ImageTop on occasions was above average and made the x-axis move faster than the check and then the check catches up again and continues moving the top image again. It is quick and quirky and like a fast skip in place on the x-axis.

This sounds very much like the scenario that I described in my previous post.
https://cplusplus.com/forum/beginner/284807/2/#msg1234701

Does ImageTop and ImageBottom have their own dt values? Why?
Normally in games and such there would only be one dt value per frame.
Last edited on
If you use sf::FloatRec, as I have seen some code that does, then every frame before you use it you have to set it = getGlobalBounds() if you scaled/transformed the original image. So really you end up using global anyway. If you don't, then yea it will shift. The setting of sf::FloatRec is very convenient if you have long class and vector calls, then you can just use

Rect1.x

instead of something like
MyVeryLongClassName::MyVeryLongFuncCall.myVeryLongArray[i].getGlobalBounds().x

I avoided it only because, I want it as fast as possible so that I can add more to the complexity as I go along, so less calls.

I have only done scaling so far, so no rotation yet and my origin remains the same at left most and top most. But if the origin is changed, lets say in the middle of the image, then I would imagine getGlobalBounds().left or .top should reference from the middle? Does it really wander away with all this considered?

My dt is once per frame and I pass it by value to my class. It tries to make the whole image movement constant, but depending on your system it can slow up or down. The image movement is pretty big at 1200 pixels (1200 x .01667) = is about 20 pixels of movement per frame (60fps), which is pretty big and combined with loss of precision can cause that stutter I imagine. Sometimes I can move it 8-10 times back and forth from one end of the screen to the other and no stutter, other times every move of back and forth across the screen can makes it glitch once.

I will try try a few things today.
Last edited on
Here is an output of frame by frame where the "MOVE" goes through the if() logic & the "NOT" goes through an else(). The skip is really there in the logic/math of the if(). At some point the loss of precision and dt act to stunt the top image back a bit and then it catches up on the next frame.

NOT
NOT
NOT
NOT
NOT
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
NOT
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
MOVE
I have to check some more, but at quick glance it might be happening when dt is at it lowest based upon what I see from this. The 2 post are continues as it moves & glitches at the NOT at the end.


NOT
dt = 0.016621
ImageTop marker if() check to move <= 1767.4
ImageBottom.left = 1846.53
ImageTop.left before move = 1827.4

NOT
dt = 0.016574
ImageTop marker if() check to move <= 1767.4
ImageBottom.left = 1826.64
ImageTop.left before move = 1827.4

NOT
dt = 0.016658
ImageTop marker if() check to move <= 1767.4
ImageBottom.left = 1806.65
ImageTop.left before move = 1827.4

NOT
dt = 0.016613
ImageTop marker if() check to move <= 1767.4
ImageBottom.left = 1786.71
ImageTop.left before move = 1827.4

MOVE
dt = 0.01672
ImageTop marker if() check to move <= 1767.4
ImageBottom.left = 1766.65
ImageTop.left before move = 1827.4
ImageTop.left after move = 1807.33 - 20.064 = 1787.27

MOVE
dt = 0.016669
ImageTop marker if() check to move <= 1747.33
ImageBottom.left = 1746.65
ImageTop.left before move = 1807.33
ImageTop.left after move = 1787.33 - 20.0028 = 1767.33

MOVE
dt = 0.016605
ImageTop marker if() check to move <= 1727.33
ImageBottom.left = 1726.72
ImageTop.left before move = 1787.33
ImageTop.left after move = 1767.4 - 19.926 = 1747.48

MOVE
dt = 0.016724
ImageTop marker if() check to move <= 1707.4
ImageBottom.left = 1706.65
ImageTop.left before move = 1767.4
ImageTop.left after move = 1747.34 - 20.0688 = 1727.27

MOVE
dt = 0.016703
ImageTop marker if() check to move <= 1687.34
ImageBottom.left = 1686.61
ImageTop.left before move = 1747.34
ImageTop.left after move = 1727.29 - 20.0436 = 1707.25

MOVE
dt = 0.016582
ImageTop marker if() check to move <= 1667.29
ImageBottom.left = 1666.71
ImageTop.left before move = 1727.29
ImageTop.left after move = 1707.39 - 19.8984 = 1687.49

MOVE
dt = 0.016697
ImageTop marker if() check to move <= 1647.39
ImageBottom.left = 1646.67
ImageTop.left before move = 1707.39
ImageTop.left after move = 1687.36 - 20.0364 = 1667.32

MOVE
dt = 0.016654
ImageTop marker if() check to move <= 1627.36
ImageBottom.left = 1626.69
ImageTop.left before move = 1687.36
ImageTop.left after move = 1667.37 - 19.9848 = 1647.39

MOVE
dt = 0.016713
ImageTop marker if() check to move <= 1607.37
ImageBottom.left = 1606.63
ImageTop.left before move = 1667.37
ImageTop.left after move = 1647.32 - 20.0556 = 1627.26

MOVE
dt = 0.016695
ImageTop marker if() check to move <= 1587.32
ImageBottom.left = 1586.6
ImageTop.left before move = 1647.32
ImageTop.left after move = 1627.28 - 20.034 = 1607.25

MOVE
dt = 0.016601
ImageTop marker if() check to move <= 1567.28
ImageBottom.left = 1566.68
ImageTop.left before move = 1627.28
ImageTop.left after move = 1607.36 - 19.9212 = 1587.44

MOVE
dt = 0.016617
ImageTop marker if() check to move <= 1547.36
ImageBottom.left = 1546.74
ImageTop.left before move = 1607.36
ImageTop.left after move = 1587.42 - 19.9404 = 1567.48

MOVE
dt = 0.01671
ImageTop marker if() check to move <= 1527.42
ImageBottom.left = 1526.69
ImageTop.left before move = 1587.42
ImageTop.left after move = 1567.37 - 20.052 = 1547.32

MOVE
dt = 0.01669
ImageTop marker if() check to move <= 1507.37
ImageBottom.left = 1506.66
ImageTop.left before move = 1567.37
ImageTop.left after move = 1547.34 - 20.028 = 1527.31

MOVE
dt = 0.016623
ImageTop marker if() check to move <= 1487.34
ImageBottom.left = 1486.71
ImageTop.left before move = 1547.34
ImageTop.left after move = 1527.39 - 19.9476 = 1507.45

MOVE
dt = 0.016714
ImageTop marker if() check to move <= 1467.39
ImageBottom.left = 1466.65
ImageTop.left before move = 1527.39
ImageTop.left after move = 1507.34 - 20.0568 = 1487.28

MOVE
dt = 0.016638
ImageTop marker if() check to move <= 1447.34
ImageBottom.left = 1446.69
ImageTop.left before move = 1507.34
ImageTop.left after move = 1487.37 - 19.9656 = 1467.41

MOVE
dt = 0.016656
ImageTop marker if() check to move <= 1427.37
ImageBottom.left = 1426.7
ImageTop.left before move = 1487.37
ImageTop.left after move = 1467.38 - 19.9872 = 1447.4

MOVE
dt = 0.016678
ImageTop marker if() check to move <= 1407.38
ImageBottom.left = 1406.69
ImageTop.left before move = 1467.38
ImageTop.left after move = 1447.37 - 20.0136 = 1427.36

MOVE
dt = 0.016713
ImageTop marker if() check to move <= 1387.37
ImageBottom.left = 1386.63
ImageTop.left before move = 1447.37
ImageTop.left after move = 1427.31 - 20.0556 = 1407.26

MOVE
dt = 0.016795
ImageTop marker if() check to move <= 1367.31
ImageBottom.left = 1366.48
ImageTop.left before move = 1427.31
ImageTop.left after move = 1407.16 - 20.154 = 1387.01

MOVE
dt = 0.016521
ImageTop marker if() check to move <= 1347.16
ImageBottom.left = 1346.65
ImageTop.left before move = 1407.16
ImageTop.left after move = 1387.34 - 19.8252 = 1367.51

MOVE
dt = 0.016672
ImageTop marker if() check to move <= 1327.34
ImageBottom.left = 1326.65
ImageTop.left before move = 1387.34
ImageTop.left after move = 1367.33 - 20.0064 = 1347.32

MOVE
dt = 0.01659
ImageTop marker if() check to move <= 1307.33
ImageBottom.left = 1306.74
ImageTop.left before move = 1367.33
ImageTop.left after move = 1347.42 - 19.908 = 1327.51

MOVE
dt = 0.016643
ImageTop marker if() check to move <= 1287.42
ImageBottom.left = 1286.77
ImageTop.left before move = 1347.42
ImageTop.left after move = 1327.45 - 19.9716 = 1307.48

MOVE
dt = 0.01676
ImageTop marker if() check to move <= 1267.45
ImageBottom.left = 1266.65
ImageTop.left before move = 1327.45
ImageTop.left after move = 1307.34 - 20.112 = 1287.23

MOVE
dt = 0.016589
ImageTop marker if() check to move <= 1247.34
ImageBottom.left = 1246.75
ImageTop.left before move = 1307.34
ImageTop.left after move = 1287.43 - 19.9068 = 1267.52

MOVE
dt = 0.01678
ImageTop marker if() check to move <= 1227.43
ImageBottom.left = 1226.61
ImageTop.left before move = 1287.43
ImageTop.left after move = 1267.29 - 20.136 = 1247.16

MOVE
dt = 0.016662
ImageTop marker if() check to move <= 1207.29
ImageBottom.left = 1206.62
ImageTop.left before move = 1267.29
ImageTop.left after move = 1247.3 - 19.9944 = 1227.31

MOVE
dt = 0.016602
ImageTop marker if() check to move <= 1187.3
ImageBottom.left = 1186.69
ImageTop.left before move = 1247.3
ImageTop.left after move = 1227.38 - 19.9224 = 1207.46

MOVE
dt = 0.016638
ImageTop marker if() check to move <= 1167.38
ImageBottom.left = 1166.73
ImageTop.left before move = 1227.38
ImageTop.left after move = 1207.41 - 19.9656 = 1187.45

MOVE
dt = 0.016791
ImageTop marker if() check to move <= 1147.41
ImageBottom.left = 1146.58
ImageTop.left before move = 1207.41
ImageTop.left after move = 1187.26 - 20.1492 = 1167.11

MOVE
dt = 0.016558
ImageTop marker if() check to move <= 1127.26
ImageBottom.left = 1126.71
ImageTop.left before move = 1187.26
ImageTop.left after move = 1167.39 - 19.8696 = 1147.52

MOVE
dt = 0.016756
ImageTop marker if() check to move <= 1107.39
ImageBottom.left = 1106.6
ImageTop.left before move = 1167.39
ImageTop.left after move = 1147.29 - 20.1072 = 1127.18

MOVE
dt = 0.016765
ImageTop marker if() check to move <= 1087.29
ImageBottom.left = 1086.48
ImageTop.left before move = 1147.29
ImageTop.left after move = 1127.17 - 20.118 = 1107.05

MOVE
dt = 0.01652
ImageTop marker if() check to move <= 1067.17
ImageBottom.left = 1066.66
ImageTop.left before move = 1127.17
ImageTop.left after move = 1107.34 - 19.824 = 1087.52


...........(continue)

........(continue)
MOVE
dt = 0.016571
ImageTop marker if() check to move <= 1047.34
ImageBottom.left = 1046.78
ImageTop.left before move = 1107.34
ImageTop.left after move = 1087.46 - 19.8852 = 1067.57

MOVE
dt = 0.016802
ImageTop marker if() check to move <= 1027.46
ImageBottom.left = 1026.61
ImageTop.left before move = 1087.46
ImageTop.left after move = 1067.3 - 20.1624 = 1047.13

MOVE
dt = 0.016532
ImageTop marker if() check to move <= 1007.3
ImageBottom.left = 1006.77
ImageTop.left before move = 1067.3
ImageTop.left after move = 1047.46 - 19.8384 = 1027.62

MOVE
dt = 0.016781
ImageTop marker if() check to move <= 987.458
ImageBottom.left = 986.638
ImageTop.left before move = 1047.46
ImageTop.left after move = 1027.32 - 20.1372 = 1007.18

MOVE
dt = 0.016665
ImageTop marker if() check to move <= 967.321
ImageBottom.left = 966.64
ImageTop.left before move = 1027.32
ImageTop.left after move = 1007.32 - 19.998 = 987.325

MOVE
dt = 0.016577
ImageTop marker if() check to move <= 947.323
ImageBottom.left = 946.747
ImageTop.left before move = 1007.32
ImageTop.left after move = 987.431 - 19.8924 = 967.539

MOVE
dt = 0.016673
ImageTop marker if() check to move <= 927.431
ImageBottom.left = 926.74
ImageTop.left before move = 987.431
ImageTop.left after move = 967.423 - 20.0076 = 947.416

MOVE
dt = 0.016789
ImageTop marker if() check to move <= 907.423
ImageBottom.left = 906.593
ImageTop.left before move = 967.423
ImageTop.left after move = 947.276 - 20.1468 = 927.13

MOVE
dt = 0.016525
ImageTop marker if() check to move <= 887.276
ImageBottom.left = 886.763
ImageTop.left before move = 947.276
ImageTop.left after move = 927.446 - 19.83 = 907.616

MOVE
dt = 0.017379
ImageTop marker if() check to move <= 867.446
ImageBottom.left = 865.908
ImageTop.left before move = 927.446
ImageTop.left after move = 906.592 - 20.8548 = 885.737

NOT
dt = 0.015978
ImageTop marker if() check to move <= 846.592
ImageBottom.left = 846.734
ImageTop.left before move = 906.592

MOVE
dt = 0.017188
ImageTop marker if() check to move <= 846.592
ImageBottom.left = 826.109
ImageTop.left before move = 906.592
ImageTop.left after move = 885.966 - 20.6256 = 865.34
I just wanted to investigate this further, but like I said before I could make the ImageTop move based on the bottom scale and not its own .left() position.

Another thing I could try to do is to add a bool for a lock that once it reaches that threshold then it no longer checks the if().

But I wanted to investigate this some more to learn why exactly it did not work, I mean it really looks like it should just work, right? Sometimes things look like they should work on paper and then you run them...


Does not always happen when dt is lowest either, but it is more likely to occur when it is lowest. Sometimes the dt can be ~0.015 and it moves fine without a glitch too. A collection of dt during the skip (NOT's) below.


MOVE
dt = 0.017806
ImageTop marker if() check to move <= 1304.64
ImageBottom.left = 1301.98
ImageTop.left before move = 1364.64
ImageTop.left after move = 1343.27 - 21.3672 = 1321.91

NOT
dt = 0.015526
ImageTop marker if() check to move <= 1283.27
ImageBottom.left = 1283.35
ImageTop.left before move = 1343.27

MOVE
dt = 0.017363
ImageTop marker if() check to move <= 1283.27
ImageBottom.left = 1262.51
ImageTop.left before move = 1343.27
ImageTop.left after move = 1322.44 - 20.8356 = 1301.6
_______________________________________________________

MOVE
dt = 0.016751
ImageTop marker if() check to move <= 1423.53
ImageBottom.left = 1423.3
ImageTop.left before move = 1483.53
ImageTop.left after move = 1463.42 - 20.1012 = 1443.32

NOT
dt = 0.016526
ImageTop marker if() check to move <= 1403.42
ImageBottom.left = 1403.47
ImageTop.left before move = 1463.42

MOVE
dt = 0.016911
ImageTop marker if() check to move <= 1403.42
ImageBottom.left = 1383.18
ImageTop.left before move = 1463.42
ImageTop.left after move = 1443.13 - 20.2932 = 1422.84

_______________________________________________________
MOVE
dt = 0.017371
ImageTop marker if() check to move <= 1251.02
ImageBottom.left = 1249.64
ImageTop.left before move = 1311.02
ImageTop.left after move = 1290.17 - 20.8452 = 1269.33

NOT
dt = 0.015957
ImageTop marker if() check to move <= 1230.17
ImageBottom.left = 1230.49
ImageTop.left before move = 1290.17

MOVE
dt = 0.016674
ImageTop marker if() check to move <= 1230.17
ImageBottom.left = 1210.48
ImageTop.left before move = 1290.17
ImageTop.left after move = 1270.17 - 20.0088 = 1250.16


_______________________________________________________
MOVE
dt = 0.016766
ImageTop marker if() check to move <= 1050.69
ImageBottom.left = 1050.35
ImageTop.left before move = 1110.69
ImageTop.left after move = 1090.57 - 20.1192 = 1070.45

NOT
dt = 0.016481
ImageTop marker if() check to move <= 1030.57
ImageBottom.left = 1030.58
ImageTop.left before move = 1090.57

MOVE
dt = 0.016832
ImageTop marker if() check to move <= 1030.57
ImageBottom.left = 1010.38
ImageTop.left before move = 1090.57
ImageTop.left after move = 1070.37 - 20.1984 = 1050.17
Last edited on
SubZeroWins wrote:
If you use sf::RectangleShape, as I have seen some code that does, then every frame before you use it you have to set it = getGlobalBounds() if you scaled/transformed the original image. So really you end up using global anyway. If you don't, then yea it will shift. The setting of sf::RectangleShape is very convenient if you have long class and vector calls, then you can just use
Rect1.x
instead of something like
MyVeryLongClassName::MyVeryLongFuncCall.myVeryLongArray[i].getGlobalBounds().x

I have no idea what you're talking about. Are you perhaps confusing sf::RectangleShape with sf::FloatRec? sf::RectangleShape inherits (indirectly) from sf::Drawable and sf::Transformable just like sf::Sprite does.

https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1RectangleShape.php

SubZeroWins wrote:
But if the origin is changed, lets say in the middle of the image, then I would imagine getGlobalBounds().left or .top should reference from the middle?

In that case the middle of the image would be at the position given by getPosition().
getGlobalBounds().left would be equal to getPosition().x - getGlobalBounds().width / 2.
getGlobalBounds().top would be equal to getPosition().y - getGlobalBounds().height / 2.

SubZeroWins wrote:
Does it really wander away with all this considered?

Yes, if the origin is in the middle of the image and you call
 
img.setPosition(img.getGlobalBounds().left, img.getGlobalBounds().top);
that would make the image "wander away" because getGlobalBounds().left is smaller than getPosition().x and getGlobalBounds().top is smaller than getPosition().y. If there is no other transformation in use that will essentially move the center of the image to the top-left corner of the image so if you call this repeatedly it will look as if the image moves in a left-up direction.

SubZeroWins wrote:
combined with loss of precision can cause that stutter I imagine

The way this thread has turned out I'm no longer so sure this problem has anything to do with lack of precision. It seems to have more to do with your "logic" not being perfect.
Last edited on
It looks like your output for "ImageTop.left after move" is incorrect (perhaps because it is placed after the code that updates ImageTop.left).

If just a single "NOT" is all it takes for you to notice that something is wrong then I can understand why it is happening.

Let me first rewrite this if condition
 
if (ImageBottom.getGlobalBounds().left <= ImageTop.getGlobalBounds().left - 0.1f * ImageTop.getGlobalBounds().width)
to
 
if (ImageBottom.getGlobalBounds().left + 0.1f * ImageTop.getGlobalBounds().width <= ImageTop.getGlobalBounds().left)

Now, what's on the left side of <= is the target position that you don't want to move past. If you print this value on each iteration I think you will see that you do move past it. To prevent that you should update your move update code so that you never move past that position.

I think something like the following should work:

1
2
3
4
5
float targetX = ImageBottom.getGlobalBounds().left + 0.1f * ImageTop.getGlobalBounds().width;
if (targetX <= ImageTop.getGlobalBounds().left)
{
	ImageTop.setPosition(std::max(targetX, ImageTop.getGlobalBounds().left - m_SpeedScalesMovingRow * dt.asSeconds()), ImageTop.getGlobalBounds().top);
}
Last edited on

I have no idea what you're talking about. Are you perhaps confusing sf::RectangleShape with sf::FloatRec? sf::RectangleShape inherits (indirectly) from sf::Drawable and sf::Transformable just like sf::Sprite does.

My apologies, I was running on little sleep. Yes my comment has to do with sf::FloatRec as I have seen that used in a sample code. I will change my comment above to prevent any confusion. I am trying to learn C++ and this graphics manipulation too and it can get daunting.


Going back to the problem. If outside of C++ someone said I have a top image and bottom image and I will move the bottom image and the top can only move if the bottom left is <= to the top left. Then at some point you say stop and the if becomes true. Then if you subtract a number (say -20 or any number you can think of) from the top and bottom image, then the <= is ALWAYS true from that point on. Same should be true with my code.

The (- Speed * dt.asSeconds()) represents this number that is to be subtracted from the top and bottom. I have checked and dt it is the same for both images always and it is "Time dt = clock.restart();" only in the update section once and the speed is always 1200.0f.

I could move the images back and forth across from one end of the screen to the other multiple times and some of the runs did not produce the stuttering or glitch. Sometimes 8-9 times, sometimes 15-20 times back and forth from one end to the other and no stutter, no problem. In fact the entire time I had 5 images stacked on top of one another with the same code and offset differently just to see what they would do. The result was more random as if dependent on the difference between top marker and actual bottom left and some loss of precision.
If you look at the <<<<<< arrows below in the "NOT" the glitch always happens when the difference is the smallest. Look at those same values in the longer list of "MOVE" section where the glitch does not happen and those differences are much larger.


MOVE
dt = 0.017806
ImageTop marker if() check to move <= 1304.64
ImageBottom.left = 1301.98
ImageTop.left before move = 1364.64
ImageTop.left after move = 1343.27 - 21.3672 = 1321.91

NOT
dt = 0.015526
ImageTop marker if() check to move <= 1283.27<<<<<<<<<<<<<<<<<<<<<<<<
ImageBottom.left = 1283.35<<<<<<<<<<<<<<<<<<<<<<<<
ImageTop.left before move = 1343.27

MOVE
dt = 0.017363
ImageTop marker if() check to move <= 1283.27
ImageBottom.left = 1262.51
ImageTop.left before move = 1343.27
ImageTop.left after move = 1322.44 - 20.8356 = 1301.6
_______________________________________________________

MOVE
dt = 0.016751
ImageTop marker if() check to move <= 1423.53
ImageBottom.left = 1423.3
ImageTop.left before move = 1483.53
ImageTop.left after move = 1463.42 - 20.1012 = 1443.32

NOT
dt = 0.016526
ImageTop marker if() check to move <= 1403.42<<<<<<<<<<<<<<<<<<<<<<<<
ImageBottom.left = 1403.47<<<<<<<<<<<<<<<<<<<<<<<<
ImageTop.left before move = 1463.42

MOVE
dt = 0.016911
ImageTop marker if() check to move <= 1403.42
ImageBottom.left = 1383.18
ImageTop.left before move = 1463.42
ImageTop.left after move = 1443.13 - 20.2932 = 1422.84

_______________________________________________________
MOVE
dt = 0.017371
ImageTop marker if() check to move <= 1251.02
ImageBottom.left = 1249.64
ImageTop.left before move = 1311.02
ImageTop.left after move = 1290.17 - 20.8452 = 1269.33

NOT
dt = 0.015957
ImageTop marker if() check to move <= 1230.17<<<<<<<<<<<<<<<<<<<<<<<<
ImageBottom.left = 1230.49<<<<<<<<<<<<<<<<<<<<<<<<
ImageTop.left before move = 1290.17

MOVE
dt = 0.016674
ImageTop marker if() check to move <= 1230.17
ImageBottom.left = 1210.48
ImageTop.left before move = 1290.17
ImageTop.left after move = 1270.17 - 20.0088 = 1250.16


_______________________________________________________
MOVE
dt = 0.016766
ImageTop marker if() check to move <= 1050.69
ImageBottom.left = 1050.35
ImageTop.left before move = 1110.69
ImageTop.left after move = 1090.57 - 20.1192 = 1070.45

NOT
dt = 0.016481
ImageTop marker if() check to move <= 1030.57<<<<<<<<<<<<<<<<<<<<<<<<
ImageBottom.left = 1030.58<<<<<<<<<<<<<<<<<<<<<<<<
ImageTop.left before move = 1090.57

MOVE
dt = 0.016832
ImageTop marker if() check to move <= 1030.57
ImageBottom.left = 1010.38
ImageTop.left before move = 1090.57
ImageTop.left after move = 1070.37 - 20.1984 = 1050.17


The NOT skips a frame and misses ~20 pixels of movement and it produces an ugly jump.
In fact, I would not even get the below to work without glitching every so often in the same way.

1
2
3
4
if (ImageBottom.getGlobalBounds().left <= ImageTop.getGlobalBounds().left)
{
	ImageTop.setPosition(ImageTop.getGlobalBounds().left - 20.0f, ImageTop.getGlobalBounds().top);		
}



Anyway, I got it to work that night by adding a bool check. If the if() statement goes through then it locks it and no longer checks thereafter, no need to as we already know it is <= and should just move at constant speed. The right arrow key unlocks it and it is ready for the next left move. Convenient this way because I can now implement code to drag the top image gradually and unnoticeable closer to the bottom image without the user noticing and probably do some unforeseen transformations too.

Know any good feeling formulas to drag images closer that are 20 pixels apart? I will have to play around with that. There are sometimes in apps or games that such dragging just feels good and right if you know what I mean.

Your addition instead of subtraction in your modified if() statement was designed by choice to reduce loss of precision? Does an addition of floats produce less loss than a subtraction at times? I really need to find some good reading book or material solely on floats.

Thanks for your help.
Last edited on
Pages: 123