12

I am experimenting with lidgren in XNA and I'm having some issues with the 'lag'.

I've downloaded their XNA sample and noticed that even their sample lags. The thing is, the movement is not smooth on the other side, and I'm trying this on a LAN (on the same computer actually) not over the internet.

Has any had the same issues as regards unsmooth movement due to a lagging connection with lidgren and XNA ?

Jonas
  • 121,568
  • 97
  • 310
  • 388
Andreas Grech
  • 105,982
  • 98
  • 297
  • 360

2 Answers2

38

The sample you linked directly sets the position to whatever it receives from the network, this is a bad idea for a multiplayer game!

What you should do in a real game is interpolate between the local position and the remote position. So, your receive method would look a little like this:

void Receive(packet)
{
    unit.RemoteX = packet.Read_X_Position();
    unit.RemoteY = packet.Read_Y_Position();
}

This has no affect on the local position on the unit, instead in your update method (every frame), you move the local position towards the remote position:

void Interpolate(deltaTime)
{
    difference = unit.RemoteX - unit.LocalX
    if (Math.Abs(difference) < threshold)
        unit.LocalX = unit.RemoteX
    else
        unit.LocalX += difference * deltaTime * interpolation_constant
}

You then display the "local" position of the unit, this achieves lagless movement like so:

  1. If the unit position is almost at the remote position, it will jump to the remote position (however, it will jump such a tiny distance that it won't look laggy).
  2. If the difference is too big to jump, then move slowly towards the position you should be in.

Since the unit moves smoothly towards where it should be, it looks like there is no lag at all!

The interpolation constant controls how fast the local and remote positions will converge:

  • 0: Ignore network updates
  • Small: Snap into place very quickly (possibly look laggy)
  • Large: Slide slowly into place, looks smooth but may feel unresponsive

You need to choose a compromise somewhere in between these options.

There are some other things to consider when implementing this kind of system, for example you often want an upper limit on how far apart units can be from their remote position otherwise the local and remote state can become "unstuck" in some situations. If they are too far apart (which should never happen except in cases of extreme lag) you can either halt the game and tell the user it's too laggy, or jump the unit straight into position, which will look laggy but at least the game will continue.

Addendum: Rereading this answer, it occurs to me that an enhancement would be to track time differences. If you know (roughly) what the lag is in the system, then you know that when you receive a packet with a remote position in you know roughly how far into the past that packet is from. If you send remote velocity too, you can predict where the object is now (assuming constant velocity). This may make the difference between estimated local state and true remote state smaller in some games, in other games (where you have lots of changing velocities) it might make things worse.

Martin
  • 12,469
  • 13
  • 64
  • 128
  • +1: Thanks for your answer; it's already given me some insight – Andreas Grech Jul 18 '10 at 20:22
  • 1
    Believe me, I was going to accept this answer :-) I can't thank you enough for your email collaboration as well. – Andreas Grech Jul 20 '10 at 10:45
  • @Martin Thanks for your insight! In order for the interpolation_constant to work correctly, as per #2, wouldn't that mean deltaTime is always 1? Which has me wondering what the purpose of the deltaTime is here? – J.C. Jul 02 '13 at 14:49
  • deltaTime (dT) is the elapsed time since the last frame. This is important because if your game is running at 30fps you're going to have a large dT and thus take large steps per frame. If your game is running at 30000 fps then you'll have a very small dT and take very small steps per frame. Basically dT makes the interpolation (mostly) frame rate independent. – Martin Jul 02 '13 at 15:34
  • @Martin, thanks. Just curious though, what does the `threshold` represent? – NiCk Newman Jun 07 '16 at 12:40
  • 1
    @NiCkNewman The threshold is when the two things are so close you can just snap to the network position without anyone noticing. If your interpolation system is good enough it can basically be set as arbitrarily low as you like. – Martin Jun 07 '16 at 12:50
  • @Martin Awww I see. Got it. I'm sending x,y positions every 250ms, and I am getting something like [this](https://i.gyazo.com/d66434638e2238093c8f0cf5e0e9c7c9.gif), not sure if you can see it, but the character kind of "jumps", if you will after the `unit.RemoteX` gets updated. Any idea on this or should I open a new question? :) – NiCk Newman Jun 07 '16 at 12:56
  • 1
    That could be one of two things. Either: 1) You need to tweak your interpolation constants a bit or 2) this approach is fundamentally limited and you need to implement what I added in my addendum. basically you send the motion vectors along and predict how the player will move, so you can do more accurate local interpolation of remote state. – Martin Jun 07 '16 at 19:06
  • 2
    I don't agree with "with constant 1 it will teleport straight to the network position" – Dmytro Mar 15 '19 at 15:39
  • Yeah you're right, constant 1 will interpolate to the position over the course of a second. It would only teleport is `deltaTime` weren't there. – Martin May 17 '19 at 02:32
  • 1
    Great answer! It should be Math.abs(difference) in the if-condition, though. –  May 25 '20 at 13:58
  • 1
    In my implementation of this algorithm the movement acquires some friction, which is nice in most games but not always. I think this is because this is a linear interpolation in each update loop, so it becomes non-linear overall since the differences decrease (I hope it's clear what I mean). –  May 25 '20 at 14:09
  • Is there any way to make the movement linear? The movement becomes linear-like when we increase the interpolation constant (to values like 10), but I think it's not safe to use constants > 1 here, and it only approximates a linear movement. –  May 25 '20 at 14:10
1

I've been looking at writing a multiplayer fps game, starting with a demo of just moving some cubes around and replicating the position/rotations on another machine, which is in a spectator mode.

I'm using your code sample above and it's working well (I've had to tweak the interpolation constant higher than 1 to make it look smooth).

I've seen a few interpolation examples which take into account the time difference between the current time and the time stamp on the received message.

I see this code does not use the time difference, so interpolation will take as long as it needs to, to get to the target value (or at least within the threshold value to then snap into position). My question is, is there any advantage to this?

Many thanks.

Prometheus3k
  • 143
  • 2
  • 7