1
\$\begingroup\$

I am implementing a pretty straightforward client/server multiplayer architecture with Socket.IO and am having an issue where my client framerate seems to be faster than the servers. I have both interval loops set at 1000 / 30 yet they quickly diverge, even on my local machine. The code is simple in the example (just increase position.x by a constant on each tick), so there is no heavy computation that should slow it down. I expect them to be off but I don't expect this distance to increase over time.

Is this minor tick difference something that's inescapable? I can do server reconciliation but there is snapping every few seconds. This is how it looks without any reconciliation:

(red is the client, blue is the server)

I know there is an alternative implementation where I would multiply the constant (which is added to position) by the timestep on each frame, thereby syncing the two. This actually more or less works, but the problem with that approach is that the game logic I am implementing has the players moving on a fixed/precise grid, and when the position updates by long floats this is difficult to enforce.

Any suggestions?

Link to full example code: here.

\$\endgroup\$
1
\$\begingroup\$

I notice you're using setInterval to time your game loop. Javascript's timing functions are imprecise, depends on the browser and prone to drift.

It's best if you use an accumulator in your time step. Accumulate the amount of time elapsed since the last update, and update depending on whether your timestep is fixed or variable. That is:

If your game has a fixed timestep:

while(timeSinceLastUpdate > frameDuration) {
    update()
    timeSinceLastUpdate -= frameDuration;
}

If your game has a variable timestep:

update(timeSinceLastUpdate)

...

player.position.x += PLAYER_SPEED * timeSinceLastUpdate

I encourage you to use a good game framework which should have handled this complexity for you. For example, here's Phaser's time step implementation: https://github.com/photonstorm/phaser/blob/master/src/boot/TimeStep.js

With this your server and clients should be more or less synced. But it's good practice to perform server reconciliation anyway, as it minimises the damage misbehaving clients can cause (overloaded client, or cheating).

Here's some useful reading: Fix Your Timestep! on Gaffer On Games

\$\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.