1
\$\begingroup\$

I am implementing client-side prediction and an authoritative server multiplayer architecture. I am following along with the series of articles from http://www.gabrielgambetta.com/entity-interpolation.html

I am at a point of confusion and have a few questions.

Within my client game loop I have a sequence of actions that update the local state.

applyLocalUpdates(state, loopTime)
reconcileLastRemoteUpdate(state, loopTime)
  • applyLocalUpdates

    This updates all the entities positions based on their local physics and game logic simulation.

  • reconcileLastRemoteUpdate

    I am in the process of implementing this and is the point of confusion. My initial naive attempt takes the last received server state and sets each local entities position to that last remote one.

    This produces a choppy update effect. When each server update comes in the entities jump to match that last server position.

    This is where I am trying to add interpolation...

I have interpolation methods like vec3.lerp(a,b,t) and quat.lerp(a,b,t) which I use to update the position vector and rotation quaternion.

My unknown points are:

  1. Which values do I pass for a and b in the interpolation?

    Is this the most recent local state and the last server state?

  2. What value do I pass in for t in the interpolation?

    This I'm highly confused. Is this the difference of elapsed time between the last 2 server states?

    Is it the difference of elapsed time between the last local update and the last server update?

Additionally, should I swap the order of execution between applyLocalUpdates and reconcileLastRemoteUpdate ?

\$\endgroup\$
2
\$\begingroup\$

You want to interpolate between the last two server states, so these should be a and b. t should be a value between 0 and 1; at 0, the lerp is equal to a, at 1, it is equal to b, anything between that will result in an interpolation between them (reference). It looks like you would want to scroll t from 0 to 1 fluently while you wait for the next server state, which requires estimating the time between each update you receive from the server.

Very barebones pseudocode (requires consistent update times, which are not given in practice):

float upadteTime = pingServer()
vec3 a
vec3 b

localUpdate {
  if (serverUpdate) {
    a = b
    b = newServerState
    timeSinceLastUpdate = 0
  }

  localState = vec3.lerp(a, b, timeSinceLastUpdate / updateTime)
  timeSinceLastUpdate += deltaTime
}

This approach will, of course, double your lag, as your local state will always be between the last two server states. You could try to predict things from local state, which makes matters more complicated.

I am not sure what happens when t is not in the range 0 - 1; perhaps it could serve as a rudimentary form of prediction? You might want to try that or research on it.

\$\endgroup\$
  • \$\begingroup\$ Your answer seems to imply that I should not be applying the local simulation to remote entities. Is that correct? Just interpolating them between server states? \$\endgroup\$ – kevzettler Mar 4 '18 at 17:07
  • 1
    \$\begingroup\$ @kevzettler Sorry, I must have overread that part. Will update shortly. \$\endgroup\$ – TauCraft Mar 6 '18 at 21:25

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.