I'm currently working on 2D rigid-body physics multiplayer game using Matter.js for physics (both the client and server side) and Phaser3 for rendering. Both the server and the client run the simulation and the server is authoritative.

The whole game consists of multiplayer players (who can collide with each other) and objects (boxes, balls, etc).

For now, I'm working on the client side prediction and while I understand the main concept, I just can't get it right.

Every game tick I gather the client inputs, store them locally, timestamp them and send to the server, while at the same time I start moving the player forward (by applying force). When the server receives the inputs, it processes them (by applying the same forces to the player). The server then sends the current state (coordinates, velocity, rotation, last processed input timestamp, etc) to all players at 20hz.

This is the part where it gets tricky. What I currently do, is I force the player to the coordinates sent from the server and apply the same velocity (both X and Y). After that, I remove all locally stored inputs which are older than the last processed input and apply them instantly in a single frame, by doing multiple physics steps.

With low latency (20-30ms) it works out quite well, with some jittering when rapidly changing the player direction or when I'm colliding with other players/objects, but with higher latencies 70-110ms, the prediction goes completely off. I can see the player constantly being pulled back and forth and the whole game becomes unplayable.

I can't wrap my head around, what exactly am I doing wrong? Is client side prediction even the correct way of handling this sort of thing in a rigid-body physics-based game?

Also, I turned off state updating from the server and noticed that the position in the server and locally sometimes goes completely off, for example when I'm jumping, running and quickly changing direction. I believe that means that the physics engine is not deterministic?

  • \$\begingroup\$ When you say you collect inputs every game tick, how are you achieving this? Are you using a Delta() component? If so, have you tried multiplying the players' velocities by the Delta() value? \$\endgroup\$ – Christopher Bennett Jun 15 '19 at 1:07
  • \$\begingroup\$ @ChristopherBennett Every game tick, I check which keys the players is pressing, and then send them to the server in messages likes this - {"action": "move", "inputs": ["jump", "left", "time": <timestamp>]}. Before sending I apply velocity to the player so it starts moving right away \$\endgroup\$ – SpeekaDievs Jun 15 '19 at 6:25
  • \$\begingroup\$ Sorry. What I meant to ask is related to the game ticks. Do they run on a local time frame, or are they server dependent (ie, the next tick will only happen after a response from the server)? I'm thinking that if the latter is true, get the value of the time that has passed since the last tick (changes for each tick depending on network latency), and multiply your velocity by that value. Repeat this every for tick. This, in theory, should help keep the physics in sync with the framerate. \$\endgroup\$ – Christopher Bennett Jun 15 '19 at 11:50
  • 1
    \$\begingroup\$ I see now, phaser 3 calculates delta automatically to some extent. I have read though, that you can turn the frame rate all the way up to 240, and this may improve movement accuracy. It's in the changelog here - github.com/photonstorm/phaser/blob/master/… \$\endgroup\$ – Christopher Bennett Jun 16 '19 at 8:01
  • 1
    \$\begingroup\$ Just passing by, but felt I might as well warn you that the current structure of your input is going to hurt you in the long run. Try looking into sending delta packets (send input information if it changes, "user is pressing but" send a push button action to server, "user releases button" send a button release action). There are many techniques to reducing packet sizes. One can also be sending information as binary data. \$\endgroup\$ – Kitanga Nday Jun 16 '19 at 17:15

Your Answer

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

Browse other questions tagged or ask your own question.