16
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ 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? \$\endgroup\$ Nov 1, 2010 at 0:26
  • \$\begingroup\$ That's send in the update data that comes from the server. \$\endgroup\$
    – Ivo Wetzel
    Nov 1, 2010 at 6:28

3 Answers 3

12
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ 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. \$\endgroup\$
    – Ivo Wetzel
    Nov 2, 2010 at 3:01
  • \$\begingroup\$ 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. \$\endgroup\$
    – Nevermind
    Nov 2, 2010 at 8:46
9
\$\begingroup\$

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.

I included a lot of detail about this approach in my previous answer here

\$\endgroup\$
2
  • \$\begingroup\$ 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 :) \$\endgroup\$
    – Ivo Wetzel
    Nov 2, 2010 at 3:04
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Martin
    Nov 2, 2010 at 12:03
4
\$\begingroup\$

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

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .