Smooth multiplayer player movement (UDP network)

Started by
11 comments, last by GNPA 4 years, 8 months ago
 

I am working on a multiplayer game which uses UDP protocol in Java. I have a server and multiple clients. The clients connect to the server and they each have their player. When one client moves a player, the position of it is sent to all the other clients connected to the server. The positional data isn't sent from the client to server and then from server to all clients. It is sent directly from the client who moved the player to all other clients connected to the server. The player is then moved in all clients windows according to the positional data sent. I know packet loss exists and there is delay in receiving packets. But I dunno how other games manage to smooth out their multiplayer player movement. Can you explain how they do it and how I can go on implementing it my self.

The bottom code is happening in the client who hasn't moved. this is the client who has received the positional data of the client who HAS moved. The bottom code runs when ever the other client moves.


// here is some pseudo code of how I manage my player movement.


// This packet contains the x and y position of the player who has moved.
Packet receivedPacket = new Packet(recievedData); 

// this is the player which represents the player who has moved.
player.setX(receivedPacket.getX());
player.setY(receivedPacket.getY());

The problem is there is very laggy player movement especially if the clients are on different computers. This is most probably due to packet loss and packet delay across the network. I have tried tweaking the player's position to the position that is received by the client. But still there is some lag. Please help me.

Advertisement

At the very least, your packet will have to include the timestamp that the position was originally recorded at, so you can interpolate the timing between positions appropriately (the difference between the timestamp of each position message is what matters here). The timing difference between sequential packets between sending and receiving is one cause of jitter. Timestamped packets give you the real position curve. Use basic interpolation to match the position timing.

Then look into extrapolation, slowing, and speeding for expected packets that are delayed or lost.

Decide on an acceptable delay to use as target. Calculated connection ping time can be used for extrapolated realtime position. You can trade-off between delayed position and extrapolation jitter. Smoothly slow down and speed up the position simulation speed to match your target delay time. Extrapolate or interpolate the position based on the real position curve.

41 minutes ago, Kaetemi said:

At the very least, your packet will have to include the timestamp that the position was originally recorded at, so you can interpolate the timing between positions appropriately (the difference between the timestamp of each position message is what matters here). The timing difference between sequential packets between sending and receiving is one cause of jitter. Timestamped packets give you the real position curve. Use basic interpolation to match the position timing.

Then look into extrapolation, slowing, and speeding for expected packets that are delayed or lost.

Decide on an acceptable delay to use as target. Calculated connection ping time can be used for extrapolated realtime position. You can trade-off between delayed position and extrapolation jitter. Smoothly slow down and speed up the position simulation speed to match your target delay time. Extrapolate or interpolate the position based on the real position curve.

Thanks for the detailed explanation. What do you mean by timestamp? Is that the time that the player was moved? Can you please give me some pseudo code of how I can go about implementing it? How I can extrapolate? I have tried something like moving the player slowly towards the position received by the packet. This just makes it seem unrealistic and jittery. Please give me some pseudo code or code that you have written to do this, if you are comfortable. Thanks again.

For example, say client A sends the position. It should also send it's current time alongside it's current position (so, the time that the packet was sent, and the position at that time.)

Client B will receive a position and a timestamp. When it receives the second position it knows the exact time it took client A to move from the first to the second position, so in case the packets did not arrive cleanly, it can replay the movement at the original speed.

Extrapolating is "the same" as interpolating, but beyond the known positions. When extrapolating, you need to do additional smoothing, so start with only interpolating.

As an initial test, just for interpolation with delay, let the first timestamp you receive be your reference time. Subtract 100ms, which serves as a "delay" time difference. Let the resulting timestamp tick forward according to the local time. This will be your "replay" time. Simply keep the latest positions received from the other client in a list. Interpolate linearly between the positions that are before and after your current "replay" time. This will give you a very basic delayed interpolation.

For extra fun, realize that different computers have different ideas of the precise time. I have seen computers on the same LAN differing in more than a minute between their idea of "the time".

 

8 hours ago, Kaetemi said:

For example, say client A sends the position. It should also send it's current time alongside it's current position (so, the time that the packet was sent, and the position at that time.)

Client B will receive a position and a timestamp. When it receives the second position it knows the exact time it took client A to move from the first to the second position, so in case the packets did not arrive cleanly, it can replay the movement at the original speed.

Extrapolating is "the same" as interpolating, but beyond the known positions. When extrapolating, you need to do additional smoothing, so start with only interpolating.

As an initial test, just for interpolation with delay, let the first timestamp you receive be your reference time. Subtract 100ms, which serves as a "delay" time difference. Let the resulting timestamp tick forward according to the local time. This will be your "replay" time. Simply keep the latest positions received from the other client in a list. Interpolate linearly between the positions that are before and after your current "replay" time. This will give you a very basic delayed interpolation.

Thanks. Can you please give some pseudo code?

I cannot imagine a network beeing so laggy. Interpolation makes stuff smooth, but a 20ms ping in a local network should not be noticeable. Even WiFi should be good enough for this. Sure there is no bug?

Also one can easily send an UDP package each frame. So movement should be as smooth local as on other clients. I mean: Setup GSync or so and update all monitors on all clients at the same time. Each clients displays local player at this frame and remote players with one frame (20ms, 50fps ) delay.

No PseudoCode in this thread because the math is like 6th grade. The real problems lie elsewhere.

32 minutes ago, arnero said:

I cannot imagine a network beeing so laggy. Interpolation makes stuff smooth, but a 20ms ping in a local network should not be noticeable. Even WiFi should be good enough for this. Sure there is no bug?

Also one can easily send an UDP package each frame. So movement should be as smooth local as on other clients. I mean: Setup GSync or so and update all monitors on all clients at the same time. Each clients displays local player at this frame and remote players with one frame (20ms, 50fps ) delay.

No PseudoCode in this thread because the math is like 6th grade. The real problems lie elsewhere.

I am just setting the player's position to the one received by the packet but due to packet loss and packet delay, the movement is jittery and freakin laggy. How should I implement the interpolation. Can you please show the code even if it is sixth grade because I am in grade 11 now I think I might need a review ;)

for the moment let's jsut pretend that there is no package loss. I've pinged tons of servers in the past years and either I reach them and there is 0 package loss or the firewalls blocks me. We live in 2019, there is pratically no package loss.

Also my kids and I played super tux kart on old crappy notebooks. It displays network delay in our Wifi and it is single digit ms, 20 ms max.

Please stop supporting bad hardware or drivers. People loved NES over C64 because collision detection was without compromise. Do not compromise on the basics.

So yeah to understand the others posts use a piece of paper. One axis is time and another axis is player ordinate (x,y or z). Or orientation angle. You have for two times info and needs info for a third time. Linear interpolation. Some triangles. Some division at the end. I cannot code this from the top of my head. Mostly I do not know how to get TimeStamps. Every programming language / API uses different words. In SQL it is GetDATE() ind JS just new Date() in Basic Now OR so?

3 hours ago, Alberth said:

For extra fun, realize that different computers have different ideas of the precise time. I have seen computers on the same LAN differing in more than a minute between their idea of "the time".

 

Use the time since the game started in seconds.  t = 0 when the game starts.  If you send a packet at 20Hz, the next time will be t = 0.05 (just a gross example)

This topic is closed to new replies.

Advertisement