Inconsistent sprite velocity?

I'm moving my sprites using the following formula:

Code that I'm using (Only shows sprite's X position being calculated but Y position is also being done)

spriteGridX = 240/480;  //I start out with a virtual 'Grid' so I can scale position to all resolutions etc so 240/480 would place the sprite at the center of the screen (X)

spriteScreenX = spriteGridX * width;  //Scale to physical screen where width is the width of the current devices screen (viewport)

spriteXTime = 8f; //8 being the amount of time in seconds that this sprite will take to traverse the entire width of the screen

spriteXVel = 1/spriteXTime; //Velocity that will be used to move the sprite along the virtual grid position


So, when I need to move the sprite, I simply do the following:

spriteXGrid+= (spriteXVel * Delta) //+= for right -=for left. I'm using a fixed delta time
spriteScreenX = spriteGridX * width; //And again, convert to usable screen position for current device
drawsprite(spriteScreenX, SpriteScreenY); //Draw the sprite (drawSprite is just a method I've written to draw openGL quads and it takes the screen X and Y as coordinates - spriteScreenY not shown here but essentially same as X with height instead of width.


Problem

The above seems to work OK (if I specify, as above, 8seconds, then the sprite does indeed take 8seconds to pass the whole screen as far as I can tell).

However, a problem becomes evident when I have 2 sprites (in my case, 2 horizontally moving platforms, both starting at the outer edges of the screen - one on the left and one of the right) - these move towards each other and when they 'meet', they go back in the opposite direction, and again when they reach their initial starting positions.

After the second time, they start to move slightly out of sync and the problem accumulates. Each platform has the same time/velocity settings and it seems that a sprite over the right side of the screen moves at a very slightly different speed than the one on the left.

After the initial move, the difference between the grid positions of my 2 sprites are a follows:

Left sprite = 0.002083334 Right sprite = 0.0020834

I can't work out why there is a difference. They're using the same formula.

Of course the problem could be that they are reversing at slightly different times and not the speed as I suspect, but for now I've ruled that out as they seem to be reversing correctly.

Be grateful if anyone could assist. Thanks

Test Device: Google Nexus 10, Samsung Galaxy Ace v1

• i think it's just wrong to use fixed time-step. Use a requestAnimationFrame (or similar on Android), and compute real elapsed time, all should be better. A question how do you solve the collision ? Could show us the code ? you must compute the real point of impact and make bounce each sprite the right amount. Good luck. – GameAlchemist Dec 7 '13 at 2:34
• It appears that there are just two values affecting x position. Start both your entities at the same x value, different y values, and move them in the same direction. On every frame, in your update, test the x values against one another. Set up a breakpoint on a conditional testing where they diverge, then drill down into the values that create them. Once you find one of these diverging, rinse and repeat. You will quickly enough find the root of the problem. It is probably in one of the contributing values. – Engineer Dec 7 '13 at 16:46

3 Answers

This is probably due to floating point error. Every time you call

spriteXGrid += (spriteXVel * Delta)


you're performing an inexact arithmetic computation. The small error accumulates over time.

If your application only needs to move in X, you can get away with using an analytic solution, i.e.

curTime += Delta;
spriteXGrid = spriteVel * curTime;


If you want a more academic description of the problem, you can read What Every Computer Scientist Should Know about Floating Point Arithmetic

• I disagree. This is not an FP discrepancy. FP errors are deterministic. He's already stated that he is using exactly the same formula for each. – Engineer Dec 6 '13 at 14:46
• If one is moving to the left and one is moving to the right, you should get different errors with the signedness of your addition. – Mokosha Dec 6 '13 at 14:49
• Ah, now that's true. – Engineer Dec 6 '13 at 14:50
• My answer removed, yours +1. – Engineer Dec 6 '13 at 14:53
• Thanks for the answer, I tried it but I didn't get any joy. Sprites simply wouldn't move correctly with the code altered. But it does appear to be the 1/Time calculation - if I set the time to 10 it (result .1) it appears to work perfectly. But set to 8 (result .125) then I have problems. Thanks for the link - will check it out. – BungleBonce Dec 6 '13 at 21:23

As specified in Mokosha's answer, this is most likely due to floating point error, and it is usually unavoidable. There are however a couple of things you can do:

The first, and most obvious, is to use double instead of float (if you aren't already). But even this will only slightly improve the situation, and over a long enough period of time, inaccuracies may still occur.

The second and more robust way is to "reset" your values in some way at specific times. For example, when your objects are at their closest positions together (just before or after they both reach the center) simply take the distance of one object from the center and set the second object to the same distance on the opposite side of the center - so if one is at 240.5 set the other to 239.5 (just as an example). If you have a small enough delta time, this will usually be imperceptible to the user. Alternately you can calculate the distance between the objects and offset each by half that value from the center - so if one is at 240.5 and the other is at 239.4 the distance between them is 1.1, half of that is 0.55, so you would set the values to 240 + 0.55 = 240.55 and 240 - 0.55 = 239.45 respectively. This should further decrease the player's perception to the "correction".

You can do this "reset" at some defined interval, or each time they reach their target location. Either way it should fix your problem ;)

I finally worked it out - it was a rather silly mistake on my behalf. When I was doing:

spriteScreenX = spriteGridX * width


I was actually casting the result from a float (spriteGridX) to an int (spriteScreenX), therefore was getting inconsistent sprite movement (in pixels) between the two sprites.

I should have been rounding up down to nearest int.

Once I rounded the results, everything seems to work perfectly.