Interpolation problem... player kind of "jumps"

Started by
4 comments, last by hplus0603 14 years, 6 months ago
Hello! I've been programming network physics a lot lately and finally settled down with interpolation. I found a great explanation by hplushplus0603 over HERE of how to do it. And I've got it to work between the client and server, but I'm having a bit of a problem, it's kind of hard to explain but I'll give it a try: When a player moves, it kind of "jump" back and forth on its path (not frequently, but very often). And I've come to the conclusion that it might has to do with the package arrival, you see, the interval between packags vary a bit. And I've noticed a connection between these shifts in the package arrival interval, and the "jumps" the player gets; Because every time it shifts, the player jumps a bit. The server on the other hand sends the packages at a given interval, 50ms, but it arrives on the client between 50 and 70 ms later, I guess it has to do with latency. The problem is kind of annoying since the player first starts to move, then it very quickly jumps ahead or backwards a bit, then back again on its path. But its not a rough jump, the client interpolates the player to that off position, then back again... Is this a common issue or what? I might have done something in the wrong way in the code, I don't know, thats why I'm posting this :P Thanks a bunch!
Advertisement
That means your interpolation is not implemented sufficiently to compensate for whatever jitter you are seeing.

In general, if you interpolate between old positions, that won't happen that much, but positions will be, well, old. The way to do that is to start moving towards the position you receive, when you receive it, with a velocity that will make you arrive at that position approximately 1.25 times the average inter-packet time from now.

To extrapolate, forward, it's not that different. Calculate where you think the interpolation will next end up at -- either by looking at heading/velocity in the received packet, or by extrapolating from the last two packets. Calculate a course and velocity that will take you to that extrapolated position by a time that's, again, about 1.25 times the average inter-packet time.

Your interpolated entities should be very simple. Something like:

class InterpolatedEntity {    float3 pos;    float3 vel;  public:    void update(float dt) { pos = pos + vel * dt; }    void setNewTarget(float3 newTarget, float timeBetweenPackets) {      vel = (newTarget - pos) * (1.25f / timeBetweenPackets);    }    float3 getPosition() { return pos; }};


Each time you receive a packet, you call setNewTarget() with the position from that packet, and the average time between packets for that entity. Each time you calculate a new frame, you simply call update() and pass in the time since the last frame was calculated, and call getPosition() to get the location to draw the entity at.

That's it! Note that, because you only ever change the velocity, there will be no "jumping" of the entities; they will just turn in a different direction and move at a different speed.

The value 1.25f gives you a little bit of filtering, which means that coming to a full stop may be a drawn-out process of slowing down. If you don't want that, you can use 1.0f as your constant, but that may cause overshoot and back-pedalling when stopping instead. Your choice.
enum Bool { True, False, FileNotFound };
Yup, interpolation is the way to go. I recently had to deal with this, and here are the notes I wrote up: networking principles. If you look at the bottom of that page you'll find links to some great documents, such as Valve Software's notes, and others.

I took a note from other engines, and added "historical" interpolation. For instance, on the client I'm not exactly sure where the server thinks I am right now, but when I receive a packet from the server I know where the server thought I was when the packet was sent. And (here's the tricky part) I'll also know where the client thought it was when it sent the most recent message that the server had received when it sent its message back to the client.

Long sentence, but basically: if you know you were 1 meter off from the server a half second ago, you are probably 1 meter off now. So you can interpolate based on the most recent "known" difference between client and server positions. It can smooth out the interpolations/jumping and improve convergence to the "proper" position.

A clunky explanation but if you search around out there you'll find better examples.
Quote:Original post by hplus0603
...

Thank you once again for a quick and understandable answer!

So basically you recommend me to use this new interpolation method instead of the old one you provided me? This one seems like a way lot simpler way of doing it (no local clock or server time involved like in the other one), but if it works I'll go for it.

I however tested it out and my server got the updates and I think the positioning was pretty neat, haven't got time to test it between clients yet.

But as far as my game goes, I don't need a heavy duty interpolation, but I want it to be smooth enough to to not generate jitter and player jumps as it is right now...


Quote:Original post by tomva
...

Yes, thank you for that, I'm trying to read as much as I can to understand this :)
Ok, update!

I've integrated everything now and it works very well !
The movement is much smoother, and those "jumps" are not that visible any more.

But just another question about the latency.
I noticed that the world between the clients doesn't not match -- For example:
Player A is ahead of player B on player A's client.
But on player B's client, player A is almost aligned with player B.

I guess it always gonna be like this because of the latency, right?
The differences are not very huge, but Im just curious if it should be like so.

I know I might have to implement some sort of lag compensation to make it more fair play for the clients and compensate for this, right?

Thanks ! :) :)
Well, the code I pasted now is simpler, but it still needs a local clock (for the "dt" part and the "time between packets" part).

Yes, with interpolation between received packets, remote clients will lag on local machines (and vice versa). The more complex code used in the Entity Position Interpolation Code sample attempts to compensate for this by calculating/guessing forward in time. That makes it more sensitive to timing jitter, so if your clock management is not solid, it will not give as smooth an experience.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement