Tutoriel: jeu multi-joueurs avec javascript et socket.io (partie 1)
- julienmesser
- 26 mars 2022
- 4 min de lecture
Dernière mise à jour : 23 avr. 2022

Ce tutoriel montre comment créer un jeu multi-joueurs en utilisant Javascript et la bibliothèque "socket.io". Des connaissances basiques de programmation suffisent.
Le jeu en question est un... "casse-briques intergalactique"... un bon vieux Pong quoi...
Interaction multi-joueurs
Socket.io fournit un service de messagerie permettant de communiquer entre un serveur et un ou plusieurs clients (les joueurs).
Nous n'aurons besoin que de quelques fichiers:
server.js: il s'agit du script serveur exécuté sur un serveur web Node.js. Son rôle est de gérer la position et les actions entre les éléments du jeu et les joueurs (la balle, les raquettes).
client.js: le client se charge du rendu sur l'écran et des interactions avec le joueur.
index.html: le point d'entrée html, il contient le "canvas" - élément principal de la visualisation et il référence le module "client.js".
game-objects.js: ce "module javascript" définit le comportement des objets: la balle et les raquettes.
Environnement de développement
Pour commencer nous allons juste et tester le jeu "en local" sur votre ordinateur, plus tard nous verrons comment déployer le jeu sur internet. Avant tout il faut installer Node.js.
Une fois Node.js installé, il faut ajouter les packages suivants à partir de la ligne de commande:
npm install -save express
npm install -save socket.io
Express est un "framework" de développement web, socket-io est... nous en avons déjà parlé ci-dessus!
Le fichier "package.json" sera crée automatiquement, se chargeant de référencer vos dépendances. Pour installer et mettre à jour les dépendances, vous n'avez qu'à exécuter npm install.
Comment exécuter le jeu
Avant d'aller plus loin peut-être voulez vous démarrer le jeu?
Le code est disponible ici: https://github.com/axis68/tuto-sync-multiplayers/tree/tuto1
Le serveur peut être lancé avec la commande node server.js ou bien npm start. Le client peut être ouvert dans l'explorateur à l'addresse http://localhost.
Derrière ce lien vous trouverez une version jouable publiée sur Heroku, plus avancée que ce tuto, elle en reprend les bases. Pour le déploiement sur Heroku, j'ai écrit le tutoriel suivant en anglais: Heroku just one click away.
Le serveur, en quelques lignes de code: "server.js"
Après les imports qui vont bien, l'application "express" est démarrée, un serveur est crée (server) ainsi qu'un gestionnaire socket.io (io). Je vous joins des extraits du code:
import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';
import * as path from 'path';
console.log('starting server...');
const app = express();
var server = new createServer(app);
var io = new Server(server);
server.listen(80, function() {
console.log("Server running on port 80 (http)");
});
Le serveur contient une boucle que nous exécuterons environ 30 fois par secondes (c'est suffisant). Cette boucle gère la collision avec les bords, le déplacement de la balle et pour finir envoie la position des objets aux joueurs connectés. Voici sa structure:
setInterval(makeItLive, 1000 / 30);
function makeItLive() {
let border = ball.isReachingBorder(width, height);
// A cet endroit on va gérer ce qui se passe en cas de collision.
// Vous trouverez les détails dans le code source.
ball.moveNextPosition(width, height);
io.emit('game-position', { "ball": ball.getJSONPosition(),
"paddlePlayer1X": paddles[0].x,
"paddlePlayer1Score": paddles[0].score,
"paddlePlayer2X": paddles[1].x,
"paddlePlayer2Score": paddles[1].score});
// Commande très simple permet d'envoyer un message socket.io au format JSON
}
Les instructions suivantes permettent au client de charger le jeu. Désolé pour le code dupliqué, ce sera à améliorer à l'occasion:
const __dirname = path.resolve(path.dirname(''));
app.get("/", function(req, res) {
res.sendFile(__dirname + '/index.html');
});
app.get("/client.js", function(req, res) {
res.sendFile(__dirname + '/client.js');
});
app.get("/game-objects.js", function(req, res) {
res.sendFile(__dirname + '/game-objects.js');
});
app.get("/hall-of-fame.js", function(req, res) {
res.sendFile(__dirname + '/hall-of-fame.js');
});
Enfin le bloc suivant permet de gérer la connexion d'un client et d'écouter ses messages:
"wannaplay": par ce message le client indique son souhait de participer au jeu
"player-position": ce message gère l'envoi de la position de la raquette
io.on('connection', function(socket) {
console.log('client connected');
socket.on('disconnect', function() {
console.log('client disconnected');
});
socket.on('wannaplay', function(playerName) {
console.log('Client wanna play: ' + playerName);
// Je passe les détails de l'inscription du joueur
// message destiné uniquement au joueur:
io.to(socket.id).emit('welcome-to-the-play', whichPlayer);
// message destiné à tout le monde:
io.emit('new-player-in-game', { "playerNb": whichPlayer, "name": playerName });
});
socket.on('player-position', function(position) {
// Réagit sur une nouvelle position du joueur
});
});
Voici le fichier complet server.js.
Le côté client: la page "index.html"
La page html est réduite au minimum: quelques éléments nécessaires au jeu, en particulier le canvas pour l'affichage:
...
<canvas id="myCanvas" width="480" height="640"></canvas>
...
Notez bien l'attribut "id" qui permet d'accéder à l'élément à partir du script. Enfin nous importons la bibliothèque "socket.io" ainsi que notre script client sous forme de module:
<script src="/socket.io/socket.io.js"></script>
<script type="module" src="./client.js"></script>
Fichier complet index.html.
Le côté client: le script "client.js"
Le javascript client se charge du rendu de l'image et des interactions du joueur.
Comme pour les autres fichiers javascript, "client.js" commence par des imports:
// Javascript ES6 module for the client side
import { Ball, PaddleType, Paddle } from '/game-objects.js';
var socket = io(); // optional: url as argument
socket.on('game-position', syncFromServer);
function syncFromServer(position)
{
// Gestion des nouvelles positions reçues du serveur
};
Pour la gestion des des commandes du joueur on utilise des "listeners":
document.addEventListener("keydown", keyDownHandler, false);
function keyDownHandler(e) {
// Gestion des actions par rapport aux touches enfoncées
}
Enfin pour la boucle principale il s'agit de l'affichage qui répété 60 fois par secondes à l'aide de la fonction requestAnimationFrame(redraw);.
function draw()
{
// 1. Affiche les différents éléments du jeu
// 2. Gère le déplacement du joueur d'après les flèches du clavier
// 3. Synchronisation avec le serveur
requestAnimationFrame(draw);
}
draw();
Voici le fichier complet client.js.
Et pour finir les objets définis dans "game-objects.js"
Les classes sont définies puis exportées afin d'être disponibles dans le module appelant. Le fichier utilise la structure suivante:
class Ball {
constructor(x, y) {
this.x = x; // attributs de classe
this.y = y;
}
class Paddle {
constructor(x) {
this.x = x;
}
export {Ball, Paddle};
Fichier complet game-objects.js.
Voilà, ce tutoriel touche à sa fin, vous trouverez ci-dessous des liens qui m'ont été utiles pour sa création. Bonne continuation !
Références
Tutoriel UTube Socket.io de Mike Codeur
Tutoriel Casse-Briques 2D Mozilla
Tutoriel de création de jeux web (en anglais) de Victor Zhou
Comments