Phaser 3 + Planck.js: fast paced p2p multiplayer POC

I have created a proof of concept to see the feasibility of creating p2p HTML5 multiplayer games on a mesh network.

The communication between the browsers is done through WebRTC, with a STUN / TURN server that I have mounted on a VPS.

The signaling is done with deepstream.io or firebase (even with the LocalStorage during development).

All the management of the mesh network (signaling, connections, sending / receiving messages) is encapsulated in a library that I have written specifically for this (mplaynet).

Once the signaling has finished and the connections have been established, all traffic goes directly between the browsers.

The peers are synchronized and agree on the game start timestamp.

Once the game starts, the time is divided into slices (e.g. 100ms).

Each peer broadcast its commands -its keystrokes-, indicating the slice to which they belong. As the commands of the other players arrive from the network, they are stored in a buffer.

Each slice corresponds to a game state (world and objects from planckjs, scoreboard and commands -local and remote-).
Before calculating the next game state, the command buffer is traversed to assign them to the corresponding game state.

To calculate the next game state, It clones the current game state and physics is calculated applying the commands.

A list of the n-last slices is stored in memory.

If commands arrive from a slice prior to the current one, the history of the game states is recalculated from that slice on. Thus, all peers keep game state synchronized, despite latency.

You can configure the slice that is rendered. If it is not the latest, the rendering can interpolate between the current state and the next.

If you change the tab or minimize the browser, the gameloop stops, but the commands continue to be received over the network. When you reactivate the tab, the history of the game states of that lost period is reconstructed, thereby resynchronizing the game.

The game

The game is very simple and does not have much value.
The objective is to create the pieces so that it works in p2p multiplayer and that these pieces can be used later in more elaborate games.

When I need to generate random numbers, I use a pseudo-random algorithm with seeds (Mersenne Twister), in such a way that all pairs generate the same numbers each time.
I keep these numbers in an array in case I have to rewrite the history of the game states, recover the ones that were generated at the time.

It can be played here: mplaynet demo

The code

To see the code, open the sandbox. The interesting part is in “scene.js” which contains all the logic of the scene and the management of game states (there are other garbage tests in that sandbox).

I want to encapsulate the logic of state management in a base class “PhaserPlanckMultiplayerScene” from which your scene can inherit to facilitate the development of these types of games.

2 Likes

I have created a repo for the POC: GitHub - supertorpe/p2p-game-poc: HTML5 Multiplayer p2p (WebRTC) demo: phaser 3 as game engine + planck.js as physics engine and fixed a bug that caused desynchronization.

I have refactored the multiplayer functionality in MultiplayerScene class.
Now it is a little easier (which is not easy) to create a multiplayer scene, inheriting from MultiplayerScene and overriding the necessary methods. It is documented in the repo.

I continue with my p2p-webrtc multiplayer experiments.
This time I have rewritten the tutorial “Making your first Phaser 3 Game”.
In this version, when the bomb hits you, it takes 10 points from you but you can continue playing.
You can play here: https://fs5hq.csb.app
…and see the code in the sandbox.

This is really cool supertorpe. But is there anyway to make it respond quicker? It does feel like inputs and movements are only done every 100msec. Definitely has a jitter/lag. I’m actually very interested in using this…but for arcade type games it’s gonna need to be quicker.

Awesome work tho!

Thanks for comment! You can play with the TIMESLICE and RENDER_DELAY constants to improve responsiveness.
Keep in mind that the lower the TIMESLICE is, the more state history rewriting events will occur.
Anyway, once it starts to move, the interpolation should show more or less fluid motion. Still, there is room for improvement in the interpolation algorithm.