Nicolas Dominici

Building Multiplayer Games with Node.js and WebSockets: A Beginner’s Guide

Building Multiplayer Games with Node.js and WebSockets: A Beginner’s Guide

Multiplayer gaming is one of the most exciting aspects of modern game development, but it’s often seen as complex and intimidating. With the right tools, though, creating a real-time multiplayer experience is more achievable than you might think. Enter Node.js and WebSockets—a powerful combination for building games that sync players’ actions in real-time.

In this guide, we’ll walk you through building a simple multiplayer game, explain key concepts like WebSockets, and demonstrate how to sync game states across clients. By the end, you’ll have the skills to create your own multiplayer game from scratch.


Why Use Node.js and WebSockets for Multiplayer Games?

Node.js is a great choice for multiplayer games because it’s event-driven and non-blocking, which makes handling multiple simultaneous connections efficient. WebSockets, on the other hand, enable real-time, bidirectional communication between the server and clients—ideal for keeping players’ actions in sync.

Benefits of Node.js and WebSockets:

  • Real-Time Communication: Instant updates between players.
  • Scalability: Handles multiple connections efficiently.
  • Cross-Platform: Works seamlessly across browsers and devices.

Building a Basic Multiplayer Game: Tic-Tac-Toe

For this tutorial, we’ll create a simple tic-tac-toe game. The goal is to sync the game state between two players in real-time.


Step 1: Setting Up Your Environment

First, make sure you have the following installed:

  1. Node.js: Download and install from nodejs.org.
  2. A Code Editor: Visual Studio Code is recommended.

Create a new project and install the required packages:

mkdir multiplayer-tic-tac-toe
cd multiplayer-tic-tac-toe
npm init -y
npm install express ws

Step 2: Setting Up the Server

We’ll use Express for handling static files and ws (WebSocket library) for real-time communication. Create a server.js file:

const express = require('express');
const WebSocket = require('ws');

const app = express();
const server = require('http').createServer(app);
const wss = new WebSocket.Server({ server });

const PORT = 3000;

// Serve static files
app.use(express.static('public'));

// Handle WebSocket connections
wss.on('connection', (ws) => {
  console.log('A player connected');

  ws.on('message', (message) => {
    console.log('Received:', message);
    // Broadcast the message to all connected clients
    wss.clients.forEach((client) => {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });

  ws.on('close', () => {
    console.log('A player disconnected');
  });
});

// Start the server
server.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

Step 3: Creating the Client

In the public folder, create an index.html file with the game interface:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Tic-Tac-Toe</title>
  <style>
    #board { display: grid; grid-template-columns: repeat(3, 100px); grid-gap: 5px; }
    .cell { width: 100px; height: 100px; display: flex; justify-content: center; align-items: center; font-size: 24px; border: 1px solid #000; cursor: pointer; }
  </style>
</head>
<body>
  <h1>Tic-Tac-Toe</h1>
  <div id="board"></div>

  <script>
    const ws = new WebSocket(`ws://${window.location.host}`);
    const board = document.getElementById('board');

    // Initialize the game board
    for (let i = 0; i < 9; i++) {
      const cell = document.createElement('div');
      cell.className = 'cell';
      cell.dataset.index = i;
      board.appendChild(cell);

      cell.addEventListener('click', () => {
        ws.send(JSON.stringify({ index: i, player: 'X' }));
      });
    }

    ws.onmessage = (event) => {
      const { index, player } = JSON.parse(event.data);
      document.querySelector(`[data-index="${index}"]`).textContent = player;
    };
  </script>
</body>
</html>

Step 4: Syncing Game States

The server broadcasts players’ actions to all clients, ensuring the game state stays consistent. Add logic to prevent overwriting cells:

// Prevent overwriting cells in the client
cell.addEventListener('click', () => {
  if (!cell.textContent) {
    ws.send(JSON.stringify({ index: i, player: 'X' }));
  }
});

Step 5: Testing Your Game

  1. Start the server:
    node server.js
    
  2. Open two browser tabs at http://localhost:3000.
  3. Play the game by clicking on cells. Both tabs should sync in real-time.

Expanding the Game

Once you’ve mastered the basics, try adding:

  • Player turns: Enforce alternate turns for “X” and “O.”
  • Win conditions: Detect when a player wins or the game ends in a draw.
  • Styling and effects: Make the game visually appealing with CSS or animations.

Wrapping Up

Building multiplayer games may seem challenging, but with Node.js and WebSockets, you can create real-time experiences with ease. This tic-tac-toe example demonstrates the core concepts of syncing game states and handling player interactions. From here, you can expand into more complex games or add advanced features like matchmaking and leaderboards. Happy coding!