August 16, 2011 5

Creating Realtime Multiplayer Games using Node JS

By in gamedev, javascript

A few months ago at work, we decided to build a realtime multiplayer game for the web, and we chose to go with Node.js for our multiplayer server.
It was a pretty strong success, and was up running for several months without a single crash or restart of the Node.js process.

We decided to write our game in Node.js because we had heard of this cool platform and had been itching to use it for a while. This turned out to be a blessing because it was very easy to get into, and many interesting Node.js libraries exist to help accomplish various task. A side benefit of using node is that javascript itself is very easy to use. This allowed us to focus on the problems all realtime network games face with less fussing with the constraints or compile times of less dynamic languages.

Node.js was also very lightweight on our servers even during peek usage. On our game the node.js process was using only 1 thread and ran at about 3-4% CPU usage running 8-10 simultaneous games each with their own collision engine instance.

Writing a realtime multiplayer game – the initial (naive) approach:

var info = {};
info.position = {x:10, y:15};
info.velocity = {x:0.5,y: 0.2};
info.currentWeapon = 1;
info.radius = 10;
this.netChannel.send( info );

Server re-broadcast that info to all other clients:

function broadcastInfo( sendingClient, messageInfo )
{
     for(var aClient in allClients) {
          if(aClient != sendingClient) {
               aClient.connection.send( messageInfo );
          }
     }
}

The main problem

With this approach is that you cannot trust the users to give you correct information about where they are. A user would just tell you that they are everywhere, and they’ve hit everything and have 100% health at all times.

Another problem with this approach is that you can never represent the true motion path of an object.

This is sometimes called the ‘bouncing ball’ problem. It is caused by extrapolating the position based on the current velocity of an object until a new update is received, and then adjusting the position and velocity and extrapolating from that point until the next update. When the ball is at the apex of its parabola, the velocity is zero so when extrapolating, the ball will just appear to be stuck in the air until it suddenly appears to crash downward.

http://farm7.staticflickr.com/6186/6049891944_43367146f4_z.jpg

Finally yet another problem with this approach is packet loss. If one packet as shown by the dotted lines is dropped, the user will travel along an incorrect path for a longer period of time. OF course this time is measured in milliseconds, so it’s not the end of the world. However in action it feels wrong visually, because things don’t change position instantaneously in real life.

A Different Approach – The client/server model

During the course of development on the game we decided to take a look and see how it was generally done. After all people have been making realtime multiplayer games for a while now. We found some interesting sources of information, specifically the freely available Quakeworld source code, and some white papers from Valve.

http://farm7.staticflickr.com/6210/6049903104_eaed9fc2d2_z.jpg

In this approach there is a single authoritative server which is playing the game, and clients send only their sampled input input data. For example, I send only the fact that my spacebar key is being pressed down, and the server decided what that means in terms of the game. With this model we completely sidestep many problems of the previous implementation.

Rendering the world

Our nervous system is to work around latency. If we apply a small constant smooth latency to an object it is easy for a human being to adjust.
The key element of the puzle is that we render all clients N milliseconds backwards in time at all times. This is an arbitrary number, so I will use 75 for my example.

The key component

http://farm7.staticflickr.com/6090/6049352303_b6b58aa17c_z.jpg

  • First we setup a system in place where the client recieves high fidelity updates from the server at discrete invervals.
  • We store WorldUpdates in an array.
  • When it comes time to draw the players on the scree, we simply draw them at `currentTime-interpAmount`
  • We’ll call this value renderTime, which aain is simply the currentTime minus 75 milliseconds.
  • Each render, we first find the two updates that our render time falls between with a simple loop.
  • Once we find those two updates, we use a linear interpolation function to position our object precisely along it’s path.
  • If a packet is dropped, for example if we never recieve packet 343 on this slide, we can still render between two known packets 342 and 344

RealtimeMultiplayerNodeJS

We’re strong believers in open-source, and decided at the end of our development to clean up our code a bit and release it as an open-source project. Because we’re not good at naming things, we named it RealtimeMultiplayerNodeJS.

RealtimeMultiplayerNodeJS is a framework specifically for building HTML5 multiplayer games with the Client / Server model. In this model, connected users send only input and the game itself runs on the server.
Clients are interpolate between two known world snapshots based on the current synchronized time.

How to use

  1. Download the repository – https://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
  2. In the terminal type “node js/DemoHelloWorld/server.js”
  3. Browse to ‘/DemoHelloWorld.html’ (Note the file must be viewed from a server in order for the websocket to connect)
  4. Physics Demo:

    This demo uses a Box2D.js implementation to create a world, and show’s off the idea of synchronized physics, and taking advantage that all the simulation happens on the server.
    It also shows synchronized interaction between multiple users, and an example of sending a message to the server which it interprets back into the game.

    DemoHelloWorld:

    The most basic interesting working demo we could come up with. Objects move from left to right.
    http://farm6.static.flickr.com/5309/5694599438_6fd56e21bd_b.jpg

    DemoCircle:

    A demonstration of the engine’s simple CircleCollision engine, which can provide you with simple collision information and fires an event when two objects collide with the two objects.
    This demo also shows one implementation of having a special kind of entity which is controlled by the keyboard from a connected user. A character controlled entity
    http://farm4.static.flickr.com/3483/5694599612_1cdb1f935e_b.jpg

    Finally, just to reiterate the point here is the entity interpolation chart in ANSCII form:

                               (actual time)
     (snapshot interval)                |
             |                          |
             _    (rendered time)       |
           /   \       |                /
          v     v     /                |
    ------|-----|----v|---|----|----|--v--------->
    0.0sec  0.1sec   0.2sec   0.3sec      time
                      |                |
                       \              /
                        \------\/----/
                               |
                               |
                     (interpolation time)
    

5 Responses to “Creating Realtime Multiplayer Games using Node JS”

  1. Anand George says:

    Nice presentation. Not sure DemoHelloWorld.html needs to be viewed from a server in order for the websocket to connect. It seems to work otherwise.

    • onedayitwillmake says:

      I had a few people say that they opened the file and nothing happened, the websocket doesn’t need it – but the page can error out due to not being displayed “off a server” and attempting to load some of the files. So I just added it as a step, but you’re right it’s not relient on that :)

  2. [...] Hier ist ein Projekt mit der Source auf Github. Ansonsten einfach mal Googlen, ist eigtl alles recht bekannt. [...]

  3. Excellent post! this info will be very helpful

  4. Congratulation, very cool apresentation! tks

Leave a Reply

*