Skip to main content
GameDev.net gamedev.net
🔒 Locked

Smooth multiplayer player movement (UDP network)

Started by AliAman Aug 13, 2019 at 3:57 AM 11 replies 15.9k views
Original Post
AliAman
AliAman

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.

Kaetemi
Kaetemi

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.

AliAman
AliAman
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.

Kaetemi
Kaetemi

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.

Alberth
Alberth

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".


AliAman
AliAman
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?

arnero
arnero

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.

AliAman
AliAman
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 ;)

arnero
arnero

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?

ThorMalleuson
ThorMalleuson
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)

Kaetemi
Kaetemi
7 hours ago, arnero said:

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.

Unless you live in an overpopulated city with poor internet, an overabundance of wifi interference from neighbours, and are using a mobile hotspot as internet connection.

Yes, you can have a beefy 50mbps internet connection today with 350ms ping and 1-5% packet loss.

Also if you're using WiFi over an AP that's slightly too far from the internet router. LAN connections will go through the router regardless if they're on the same AP, and there will be packet loss (a lot of it).

9 hours ago, AliAman said:

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 ;)

Okay.

Player A sends position (5, 10) at 100050ms.

Player A sends position (5, 20) at 100100ms.

Then.

Player B receives the first position. It sets the time of player A to 99950ms (so we keep an animation clock for each remote player), 100ms earlier (buffering delay), and positions him at (5, 10).

Player B has a next frame 50ms later, it moves the animation time of player A forward to 100000ms, position stays the same.

Player B receives the second position.

Player B has a next frame 50ms later, it moves the animation time of player A forward to 100050ms, position stays the same, since it's now at the first position.

Player B has a next frame 25ms later, it moves the animation time of player A forward to 100075ms. This time is inbetween the two received positions, so the position is interpolated to (5, 15).

And so on.

The key here is, start with replicating exactly the positions and timing from the remote player, as if they're an animation timeline, with some initial delay to allow for buffering. Only once you get that working, think about extrapolating and advanced smoothing.

Quick and dirty interpolation pseudocode:


double timestamp0, timestamp1;
vector2 pos0, pos1;
double timestampNow;
double diffTotal = timestamp1 - timestamp0; // time between timestamps
if (diffTotal <= 0) return pos1; // sanity
double diffNow = timestmap1 - timestampNow; // should be between 0 and diffTotal if interpolating
double factor1 = diffNow / diffTotal; // between 0 and 1
double factor0 = 1.0 - factor1; // between 0 and 1
return (pos0 * factor0) + (pos1 * factor1); // result vector

Review the following maths:

  • Trigonometry (area, sin, cos, tan, the rest is not important). Right angled triangles are practically the same math as vector math, so you can skip ahead to vector math from there as well (vector math is 'easier').
  • Vector math (adding vectors, multiplying vectors with a factor, the length of a vector (sqrt(x²+y²), it's easy.), dot product.)
  • Matrix math (matrix * vector, matrix * matrix.) This is useful for rotations and stuff.
  • Interpolation (linear interpolation, bezier interpolation.)
  • Extrapolation
  • Approximation

And always remember: sin, cos, tan and sqrt are evil. :)

GNPA
GNPA

Based on my experience depends on the type of game you want to make multiplayer.

But if online multiplayer--unless that is a not real time game (turn based):
1-In player terminal/machine/console when action occurs do it locally (move, rotate, shoot, etc)
2-Send updated state to server
3-Server compares player position to server side infered position (server side prediction). Very simplified the players last action is likely to keep occuring (linear interpolation of movement, actions).
4-In the client side same is done to other players (client side prediction).
5-Unless great deviation occurs the server and client see this aproximate of the game state.

UPD is bether than TCP in this because TCP tries to resend data if packages do not reach target which is a problem.

Since your using Java: orbit (http://www.orbit.bio/), JGroups, GridGain (TCP only) might work, ,ZeroC - Network Your Software

A simple tuturial
https://gamedevelopment.tutsplus.com/tutorials/building-a-peer-to-peer-multiplayer-networked-game--gamedev-10074

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.