# Interpolating positions in a multiplayer game

In order to save bandwidth in my multiplayer game, I do not update every object every server tick, instead each object has an updateRate which tells the game that this object is expected to be updated every X server ticks.

When I receive an update message for an object I calculate the time I expect the next update to come in:

origin = serverCurrentPosition
diff = serverNextPosition - origin
arriveTime = now + timeBetweenTicks * updateRate


When I draw the object I calculate the time that's left till the next update and interpolate the position accordingly:

step = 100 / timeBetweenTicks * updateRate
delta = 1 - step * ((arriveTime - now) / 100)
position = origin + diff * delta


It works... but there's still a bit of jitter in the drawing, although in my theory every thing should work out fine, since the scaling should take care of some amount of lag, should it?

So the question here is, is this the best approach? Should I put actual lag into the computation? If so, how would I do that? I did some experiements, but the jitter only got worse.

• Hi Ivo. I think this is a good topic, but it's not clear what your code is doing - for example where does serverCurrentPosition, serverNextPosition, timeBetweenTicks come from? – CiscoIPPhone Nov 1 '10 at 0:26
• That's send in the update data that comes from the server. – Ivo Wetzel Nov 1 '10 at 6:28

You have jitter, because you lag is changing constantly. This means, that while server sends updates exactly every timeBetweenTicks ticks, the client receives them after some variable time. That time is probably close to timeBetweenTicks on a good connection, but not exactly equal (And besides, you may have server lag and different clock speeds on server and client).

So, when you rely on receiving the update in exactly the specified time, you constantly arrive at the destination a bit before/after the actual update. Hence, jitter.

Simple approach to reduce jitter is using "rubber-banding", which is what Martin suggests in another answer. Basically, when you receive update, you don't immediately change the object's position. Instead, if client position and server position differ only slightly, you begin interpolating client position, so that after some specified time (say, halfway to next update) client and server positions converge.

Another idea to reduce jitter in your setup: since you transmit both "current" and "next" coordinates, you can calculate the velocity of the object. Then, when update lags, you don't stop the object at its destination (i.e. "next" position), but continue moving it with the same velocity. If your objects don't change their speeds abruptly, this will really improve motion smoothness on the client.

• It's already so, that the objects don't stop, they continue to move on until the receive the next update. Also, using Hardware Acceleration on the HTML canvas seems to reduce the jitter effect quite a bit. Maybe I just got crazy after working on that thing for so long. – Ivo Wetzel Nov 2 '10 at 3:01
• That's quite possible. If turning on acceleration makes frame rate higher, then probability of handling the update info at exactly the right moment increases. – Nevermind Nov 2 '10 at 8:46

I have solved this problem before with some success with an approach I call "network shadows". I don't know if this is something other people do, but it's always worked for me.

Each entity which is being synchronised across the network has an invisible network shadow entity. When an update comes in from the network, you teleport the shadow directly to the position the network says it should be at, then you slowly interpolate the local visible entity towards the shadow over time.

• Hm, I did something like that in an earlier version ,floating point imprecision made it really bad at times, I have quite big timespans betwenn the updates, up to 300ms for some objects, but maybe I just did it wrong, I gonna give it a shot when I find some free time :) – Ivo Wetzel Nov 2 '10 at 3:04
• floating point precision really shouldn't come into this at all! Did you read my linked answer on stackoverflow? It covers all the details of implementing this kind of thing. – Martin Nov 2 '10 at 12:03

I've written an article detailing a slightly different approach, which produces very smooth results: http://www.gabrielgambetta.com/fpm3.html