1
\$\begingroup\$

In a fast-paced multiplayer game I'm working on, there is an issue with the interpolation algorithm. This interpolation is for a moving object not controlled by the local computer.

The server sends packets with the object's position at a fixed rate. (red markers) The interpolation algorithm is attempting (and failing) to create a smooth path between the red markers.

The results of this interpolation are shown by green and black markers. Green is the local position at the exact time a packet is received, and black is the local position at every frame.

Green: Local position when a packet is received (edited for clarity)

Red: Position received from packet (goal)

Blue: Line from local position to goal when packet is received

Black: Local position every frame

On a network with a realistic amount of lag and packet loss, this is the result:

Bad stuff

The local position (green&black lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

This is how it looks on a perfect network with the object moving right to left. (0 ping, 0 packet loss, etc.)

Good stuff

The code works like this:

  1. Every x ms, receive a packet with a Vector3 position
  2. Set the goal to that position
  3. Set the positionAtLastPacket to the current local position
  4. Every frame, lerp from positionAtLastPacket to goal, attempting to reach the goal approximately when the next packet should arrive.
  5. If the next packet takes longer than expected, interpolation continues past the goal and becomes extrapolation.

I believe what is happening is the extrapolation overshoots a bit to far. Over several packets, this issue compounds, causing the oscillation.

    // local transform position when the last packet arrived. Will lerp from here to the goal
    private Vector3 positionAtLastPacket;

    // location received from last packet
    private Vector3 goal;

    // time since the last packet arrived
    private float currentTime;

    // estimated time to reach goal (also the expected time of the next packet)
    private float timeToReachGoal;

    private void PacketReceived(Vector3 position, float timeBetweenPackets)
    {
        positionAtLastPacket = transform.position;

        goal = position;

        timeToReachGoal = timeBetweenPackets;
        currentTime = 0;

        Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
        Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
        Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
    }

    private void FrameUpdate()
    {
        currentTime += Time.deltaTime;

        float delta = currentTime/timeToReachGoal;
        transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);

        // current local position
        Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
    }

    /// <summary>
    /// Lerp without being locked to 0-1
    /// </summary>
    Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
    {
        return from + (to - from) * t;
    }

Any idea about what's going on?

\$\endgroup\$
  • \$\begingroup\$ "You can see it clearly in the image below" - No I can't. I have not even found Cyan yet.. "As you can see, the local position seems to oscillate around the goals" - Can not see that either .. Cyan sticks oscillates? Around red sticks? Not sure that is evident. \$\endgroup\$ – Kromster says support Monica Jun 2 '14 at 4:49
  • \$\begingroup\$ @KromStern Fixed the image. Cyan was probably a bad choice for something that needed to stand out against the sky. By "oscillate" I mean the local position whips back and forth perpendicular to the target path (red) instead of following it. \$\endgroup\$ – Ben Cracknell Jun 2 '14 at 5:52
  • \$\begingroup\$ Thanks for the edit, at least green lines are visible now ;) Still can't make any sense out of it - I just see 3 set of sticks and no idea why they are right or wrong. \$\endgroup\$ – Kromster says support Monica Jun 2 '14 at 6:06
  • \$\begingroup\$ @KromStern I'll describe it in a different way. Red lines are positions received from the server, green&black lines are positions of interpolation. This is very bad, since interpolation should be between the red lines, not all over the place. (I've also edited the post again with details on how the code works) \$\endgroup\$ – Ben Cracknell Jun 2 '14 at 7:08
  • \$\begingroup\$ Am I getting your expected result right: green lines should be aligned with objects movement, blue lines should be going along series of red lines and black lines should be in between red lines? \$\endgroup\$ – Kromster says support Monica Jun 2 '14 at 7:16
0
\$\begingroup\$

Welp, it turns out my router was messed up, causing the game to fall back on TCP without warning. Everything is working fine now, I'm just stupid.

I should have realized something was wrong when the packets started coming in like this:

enter image description here

There were many other things causing the game to fall back on TCP. Some of them are specific to TNet (my framework) but I'll list them off just in case:

  • The Unity Web player doesn't support UDP at all for security reasons.
  • Using a VPN to connect back to a server on your local network (in an attempt to test with high ping) will often cause UDP to fail. I don't know why exactly, so it might be specific to my VPN.
  • Mixing up the ports for a TNet server, or connecting on the wrong ports. It's a bit confusing to get right, so here is the correct way: (using example port numbers)

Create:

TNServerInstance.Start(TCP_PORT, UDP_PORT, null, BROADCAST_PORT);

Discovery on LAN:

(set your lobby port to BROADCAST_PORT)

Connect:

TNManager.Connect(xxx.xxx.xxx.xxx, TCP_PORT);

Overall, I highly recommend getting a VPS to host your server for testing, which would have made fixing this problem much easier to discover and find. Digital Ocean has served me well, and it only costs $5/month for more badnwidth and power than I would ever need.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.