Skip to main content

Online Card Game with Node.js and Socket.io – Episode 5

4 min read

Older Article

This article was published 13 years ago. Some information may be outdated or no longer applicable.

The game’s getting close. I’ve got a working demo now that covers the following:

  • Auto-creation of a test room that can have one table
  • Auto-creation of a test table that can have 2 players
  • Players need to enter their names to join a table
  • Basic gameplay is fully implemented but additional rules are missing
  • If the pack of cards get emptied, the discard pile is reshuffled and will become the new pack
  • Messages are passed in between the connected clients to indicated end of turn events

You might be wondering where I test all this. I’ve got a local test environment (running a heavily customised Ubuntu server) but I’ve also rolled the project out to a small group of friends using Amazon EC2. If you haven’t used EC2 before, it lets you run your own virtual machine in the cloud, accessible everywhere. And for new users, it’s free for a whole year. There’s plenty of material out there on setting up a virtual server with the right options and getting a Node.js project running. I found this post by Ben Nadel the most useful.

Here’s a screenshot of the application now (compare it with the screenshot from episode 2). The GUI’s come a long way (or should we say, WUI?).

The initial screen that players see. Both have got 5 cards assigned and the first card in the discarded pile is placed automatically.

During gameplay, you can see how many cards the other player has in their hand.

And finally, announcing the winner.

You’ve probably spotted the “It’s your turn” and “It’s your opponent’s turn” messages. Before those existed, the only indication of whose turn it was came from watching the discarded pile update or the remaining cards counter drop by one (meaning the opponent drew a card). Neither of those felt right, so a proper solution had to be built. Here’s the Messaging module, a new JavaScript class that sends messages to players connected to the websocket server. It can:

  • Send a message to every player
  • Send a message to every player but the one who initiated the conversation
  • Send a message to only one player
Messaging.prototype.sendToAll = function (event, message, socket, player) {
  for (var i = 0; i < player.length; i++) {
    socket.sockets.socket(player[i].id).emit(event, message);
  }
};

Messaging.prototype.sendToAllButPlayer = function (
  event,
  message,
  socket,
  players,
  player
) {
  for (var i = 0; i < players.length; i++) {
    if (players[i].id != player.id) {
      socket.sockets.socket(players[i].id).emit(event, message);
    }
  }
};

Messaging.prototype.sendToAPlayer = function (
  event,
  message,
  socket,
  players,
  player
) {
  for (var i = 0; i < players.length; i++) {
    if (players[i].id == player.id) {
      socket.sockets.socket(players[i].id).emit(event, message);
    }
  }
};

The server then calls the appropriate functions in the draw and play methods.

messaging.sendToAPlayer(
  'turn',
  { myturn: false },
  socket,
  room.players,
  player
);
messaging.sendToAllPlayersButPlayer(
  'turn',
  { myturn: true },
  socket,
  room.players,
  player
);

The frontend listens for the turn message and acts accordingly:

socket.on('turn', function (data) {
  if (data.myturn) {
    $('#progressUpdate').html("It's your turn.");
  } else {
    $('#progressUpdate').html("It's your opponent's turn.");
  }
});

That’s the messaging sorted. Messages now bounce between client(s) and server, keeping everything in sync.

The project’s nearly finished. Once the code is cleaned up, I’ll commit the codebase to GitHub. There’s still plenty to do though. I need to implement Room/Table creation, additional rules for the card game (there are a number of action cards which, upon being played, let the player make special requests, e.g. if an Ace is played, the player can ask for a suit, and the next player has to either play a card of the requested suit, or counter with another Ace and make a new request). The frontend needs some makeover too. Until next time!