Josh Software

Real-time Games using HTML5, WebSockets, nodejs and socket.io – Josh Software

product customization

Real-time Games using HTML5, WebSockets, nodejs and socket.io – Josh Software

Ever imagined playing a game on the web by simply logging in – no local installation required, no licenses and you can continue from where you left off! Imagine multi-player games from your browser or phone – basically ‘gaming in the cloud’. Ok – that sounded pretty cliche 🙂 But its already here folks and faster and better then we can imagine!

What started off as a proof of concept for us has quickly gathered shape to build something of real potential. What we wanted to do was

  • Launch a game on a common display in a web browser.
  • Control the game from different browsers (desktop or mobile).
  • Manage notifications between controllers and the game.
  • Ensure that no installation required what so ever, even as browser plugins.
  • Measure the latency involved.

The Initial Investigation and options

Nodejs boasts of high concurrency, is a Javascript framework and hence functional or event based programming. Sounds awesome but has a higher learning curve. socket.io works very well with WebSockets, so it would be easy to manage

EventMachine also manages high concurrency using evented I/O. Should be an ideal choice for high concurrency but how will websockets be managed easily?

Simply based on a few facts about nodejs and the new stuff we could learn and investigate , we chose nodejs – (and I am happy to say that it may have been a very prudent choice! )

These are the node modules we used:

  • socket.io – the obvious choice for WebSockets.
  • express – our choice of the Web Interface. We could have used a Rails application but seems an overkill.
  • jade – for HTML templates
  • redis – for PubSub.

Getting our act together

We wanted to build something that would give us the data we need as well as be fun! So, we decided to build a game called ‘Tapit’.

Tapit is a dance floor – a place where you can join in by clicking on a unique URL and entering your nickname. You would see your cartoon on the dancefloor and will have the controls on your mobile browser – 4 actions which will change the images on the dance-floor effectively making your cartoon dance! Everyone can have their own cartoon on the dance floor and can dance together. This creates a ‘engaged interaction game’ – where the person has to be in front of the dance floor to see his cartoon dance to his tune! A simple application with huge potential.

So, we started by setting up the node server and the node modules. We also installed Redis on our server to make the most of Redis PubSub!

To install node, npm and the node modules read these links: nodejs and  npm.

Configuring socket.io, express and redis

We can setup our node server and configure it like this:

HOST = "localhost",
PORT = "3001"

var express = require('express')
 , app = express.createServer()
 , redis = require('redis')
 , io = require('socket.io').listen(app);

const DB = redis.createClient();
io.set('log level', 1); // reduce logging

app.use(express.bodyParser());
app.use(express.static(__dirname + '/public'));
app.set('view engine', 'jade');

app.listen(PORT);

We also need to keen the Redis PubSub messaging channels open. Here is how we do this:

io.sockets.on('connection', function(socket) {
  const subscribe = redis.createClient();
  const publish = redis.createClient();

  socket.on('publish', function(channel, data) {
    publish.publish(channel, data);
  });

  socket.on('psubscribe', function(channel) {
    subscribe.psubscribe(channel);
  });

  subscribe.on("pmessage", function(pattern, channel, message) {
    socket.emit('message', { channel: channel, data: message });
  });
});

Create a new dance floor

To create a new dance floor, we need to call URL /games/new from the display machine. This creates the dance floor and gets the client side code ready to listen to new events like ‘new dancers’ or ‘change of action’.

Starting the game

To get your cartoon on the dance floor, users need to type the URL generated for that unique dancefloor on their mobile browser. This shows a screen to get your nickname, so you can identify yourself on the dance floor.

Playing the game

Once you have joined in, you should see your own avatar (cartoon) on the dance floor.

At this same time, you should see 4 controls on your mobile browser. You can tap anyone to make the cartoon on the dance floor ‘make your move’.

This is how the client side JS controls actions are controlled

$("#subscribe").submit(function() {
  socket.emit('psubscribe', $('#subscribe #channel').val());
  return false;
});

$(".action").click(function() {
  socket.emit('publish', 'game.#{gameid}.action.' + $(this).data('action'),
  JSON.stringify({ nick: "#{nick}", ts: Date.now() })
);

The websocket publishes events for a particular game. When nodejs receives this event, it publishes this on Redis PubSub. Since there are listeners connected, they receive this notification. Since listeners can be web-sockets themselves, they get a push notification on the webpage.

Performance – Latency and Concurrency

We tested out various networks, over WiFi, 3G and even on Edge network. The worse case scenario with Edge we found a latency of 200ms – probably acceptable.

When we tested for concurrency, we were easily able to scale easily to 100 ‘dancers on the dance floor’ dancing at the same time. The big issue currently is that for every subscriber I have to open a redis client. So,  I need to figure that one out. The other issue (still in debugging) was “Too many files open” exception on the node server. Again, this is not node related but a setup related issue.

Github repos

I have this game updated on github at http://github.com/joshsoftware/tapit  Feel free to fork it and play around. The live demo is hosted on http://tapit.nodejitsu.com

Where do we go from here?

This is just the beginning! Our next aim to build a multi-player game on the web. There are constraints of scale and latency – but then let us go where few men have gone before! 🙂

Update: This page has been translated into Spanish by Maria Ramos  from Webhostinghub.com