A framework for multiplayer physics simulations (read: games)
Version 0.1 - First release, pretty mediocre API but it works. Version 0.1.1 - Remove a bunch of extraneous dependencies
The main feature of multiplayer.js
is lag compensation. Using interpolation,
extrapolation and client-side prediction, the apparent effects of network
latency are minimised.
Since every game is different, multiplayer.js
doesn't mandate any particular
transport protocol or simulation engine. The only requirement is to be able to
provide it with a simple JSON representation of player states and of user input.
These objects need to be passed back and forth to instances of Server
and
Client
.
The environment running the Server
is responsible for running the canonical
game simulation (physics). It will need to take any user commands (inputs) and
generate a new game state every frame.
The environment(s) running the Client
are responsible for presenting the game
state to a player (rendering), and for running a local simulation of the game in
order to predict the player's movement during the time between receiving input
and the server acknowledging that input.
npm install multiplayer
The suggested method to wrap up this library for use in the browser is to use
browserify
. If you include this library as an npm dependency, you could do
something like the following:
var express = require('express');
var browserify = require('browserify');
var app = express.createServer();
app.listen(8080);
var bundle = browserify({
mount: '/multiplayer.js',
require: ['multiplayer']
});
app.use(bundle);
A framestamp
is a decimal value of form m.n, where:
- m is an integer referring to the frame number
- n is a decimal in the range
0.0 <= n < 1.0
, referring to a fraction of a frame's time
ie: framestamp 10.20 means frame 10, 20% of the way to frame 11
On the server: Set a constant fps, where fpsInterval = 1 / fps Each time a player command comes in: Advance the player based on the framestamp given in the command NOTE client framestamp must be <= server framestamp player.updatePhysics(dt (in milliseconds), inputs) @time += dt @position += @velocity * dt @velocity = getVelocity(inputs) Every fpsInterval: Advance the world by fpsInterval (non-player-controlled entities) Prepare and broadcast a snapshot Include entity positions, and player framestamps
On the client: Assuming the client knows server fps... Each time a snapshot comes in: Add it to a list Each graphics frame: Check for a new snapshot If there is one, set oldSnap = nextSnap, nextSnap = new snapshot If there isn't and time < nextSnap.time, don't do anything If there isn't and time > nextSnap.time, set oldSnap = nextSnap, nextSnap = null Run client-side prediction Run through the list of input commands: Remove and skip if command's framestamp <= oldSnap.players[this].frameStamp Otherwise, advance the player, using the same physics code as on the server Interpolate/extrapolate all other entities' positions Trigger events (a/v effects) Render frame