Phaser vient de franchir une étape qu'on attendait depuis des années : la version 4 est sortie le 10 avril 2026, suivie de la 4.1 fin avril et de la 4.2 « Giedi » le 19 juin. Le moteur de rendu a été entièrement réécrit, mais l'API que des milliers de développeurs connaissent par cœur, elle, n'a pas bougé. Autrement dit : c'est le bon moment pour coder son premier jeu 2D avec Phaser, sans craindre de tout devoir réapprendre dans six mois.
Ce guide part de zéro et se termine avec un petit jeu jouable dans le navigateur : un héros qui court, saute, tombe sur des plateformes et ramasse des étoiles pour marquer des points. Prévoyez une bonne heure, un éditeur de code et un peu de curiosité.
Pourquoi Phaser reste une valeur sûre en 2026
Phaser accompagne les créateurs de jeux HTML5 depuis plus de dix ans, et sa force n'a jamais été la promesse d'un rendu spectaculaire. C'est plutôt l'inverse : un cadre de travail sobre, documenté, qui tourne partout où il y a un navigateur, sans build natif, sans licence, sans abonnement. Un jeu Phaser terminé, ce sont quelques fichiers statiques qu'on dépose sur un hébergement classique.
La version 4 apporte une refonte complète du rendu WebGL, désormais organisé en nœuds de rendu indépendants, et unifie les effets et les masques de la v3 sous un système unique de filtres. Ce sont des changements profonds, mais ils restent sous le capot : sprites, scènes, groupes, physique arcade, texte, tilemaps, tout cela s'écrit exactement comme avant. Un projet Phaser 3 se migre généralement en une après-midi, et les tutoriels existants restent valables.
Si vous voulez d'abord voir à quoi ressemble le strict minimum, notre article Programmer un jeu vidéo avec Phaser : le Hello World pose les bases en quelques lignes. Ici, nous allons plus loin.
Ce qu'il faut avant de commencer
Trois choses suffisent : Node.js en version 20 ou plus récente, un éditeur de code, et une connaissance minimale de JavaScript moderne — les const, les fonctions fléchées, les objets littéraux. Aucune notion de WebGL n'est nécessaire, Phaser s'en charge.
Un point technique mérite d'être signalé tout de suite, parce qu'il fait perdre une demi-heure à presque tout le monde : un jeu Phaser doit être servi par un serveur web, même en local. Si vous ouvrez votre index.html en double-cliquant dessus, le navigateur refusera de charger les images pour des raisons de sécurité, et vous obtiendrez un écran noir sans message d'erreur clair.
Installer Phaser 4 et poser la structure du projet
Le plus simple aujourd'hui est de partir d'un projet Vite, qui fournit le serveur local et la compilation finale sans configuration :
npm create vite@latest mon-jeu -- --template vanilla
cd mon-jeu
npm install phaser@4.2.0
npm run dev
Créez ensuite un dossier public/assets/ pour vos images. Si vous n'avez pas encore de graphismes, le pack d'exemples officiel de Phaser fournit un ciel, une plateforme, une étoile et un personnage animé, largement suffisants pour ce tutoriel.
Vous préférez éviter Node ? Un simple fichier HTML et le CDN font aussi l'affaire, à condition de le servir depuis un serveur local :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Mon premier jeu</title>
<script src="https://cdn.jsdelivr.net/npm/phaser@4.2.0/dist/phaser.min.js"></script>
</head>
<body>
<div id="game"></div>
<script type="module" src="main.js"></script>
</body>
</html>
La configuration du jeu et la première scène
Tout part d'un objet de configuration. Il décrit la taille du canevas, le moteur de rendu, la gravité du monde et les scènes à charger. Ouvrez main.js :
import Phaser from 'phaser';
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'game',
backgroundColor: '#1d1d2b',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
debug: false
}
},
scene: { preload, create, update }
};
const game = new Phaser.Game(config);
Phaser.AUTO demande au moteur d'utiliser WebGL si le navigateur le permet, et de basculer sur le canvas 2D sinon. La gravité de 300 pixels par seconde au carré s'appliquera à tous les corps dynamiques : c'est elle qui fera retomber notre héros après un saut.
Une scène Phaser repose sur trois fonctions dont les noms disent bien ce qu'elles font. preload charge les ressources, create construit le monde une fois les ressources disponibles, et update s'exécute à chaque image, soixante fois par seconde. Cette séparation est la clé pour comprendre le reste : rien ne doit être chargé dans create, rien ne doit être créé dans update.
Charger les images et construire le décor
La méthode this.load empile les ressources dans une file d'attente. Chaque ressource reçoit une clé, une chaîne de caractères que vous réutiliserez ensuite partout dans le code :
function preload () {
this.load.image('ciel', 'assets/sky.png');
this.load.image('plateforme', 'assets/platform.png');
this.load.image('etoile', 'assets/star.png');
this.load.spritesheet('heros', 'assets/dude.png', {
frameWidth: 32,
frameHeight: 48
});
}
La dernière ligne mérite un mot. Une spritesheet est une seule image qui contient toutes les poses du personnage alignées côte à côte. En indiquant la largeur et la hauteur d'une case, on permet à Phaser de la découper automatiquement en images numérotées, que l'on assemblera ensuite en animations. Pour les projets plus lourds, on passe généralement à des atlas de textures — le sujet est détaillé dans notre guide complet de la gestion des assets dans Phaser.
Passons au décor. Les plateformes ne bougent jamais et ne subissent pas la gravité : ce sont des corps statiques, regroupés dans un staticGroup.
let plateformes;
function create () {
this.add.image(400, 300, 'ciel');
plateformes = this.physics.add.staticGroup();
plateformes.create(400, 568, 'plateforme').setScale(2).refreshBody();
plateformes.create(600, 400, 'plateforme');
plateformes.create(50, 250, 'plateforme');
plateformes.create(750, 220, 'plateforme');
}
Attention au refreshBody() : quand on redimensionne un corps statique, sa boîte de collision ne suit pas toute seule. Sans cet appel, le sol du bas resterait à sa taille d'origine et le héros passerait joyeusement à travers la moitié de l'écran. C'est l'un des pièges les plus classiques du moteur.
Le héros, la physique arcade et les collisions
Le personnage, lui, est un sprite dynamique : il tombe, rebondit, réagit aux collisions.
let joueur;
// à ajouter dans create()
joueur = this.physics.add.sprite(100, 450, 'heros');
joueur.setBounce(0.2);
joueur.setCollideWorldBounds(true);
this.physics.add.collider(joueur, plateformes);
this.anims.create({
key: 'gauche',
frames: this.anims.generateFrameNumbers('heros', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
this.anims.create({
key: 'face',
frames: [{ key: 'heros', frame: 4 }],
frameRate: 20
});
this.anims.create({
key: 'droite',
frames: this.anims.generateFrameNumbers('heros', { start: 5, end: 8 }),
frameRate: 10,
repeat: -1
});
La ligne décisive est this.physics.add.collider(joueur, plateformes). Elle ne fait rien de visible, mais elle installe un contrat entre deux objets : à chaque image, Phaser vérifiera s'ils se chevauchent et les repoussera proprement. Sans elle, le héros traverserait le décor comme un fantôme. Le repeat: -1 des animations signifie simplement « en boucle infinie ».
Donner le contrôle au joueur
Phaser expose les quatre flèches directionnelles et la barre d'espace en une seule ligne :
let touches;
// dans create()
touches = this.input.keyboard.createCursorKeys();
function update () {
if (touches.left.isDown) {
joueur.setVelocityX(-160);
joueur.anims.play('gauche', true);
} else if (touches.right.isDown) {
joueur.setVelocityX(160);
joueur.anims.play('droite', true);
} else {
joueur.setVelocityX(0);
joueur.anims.play('face');
}
if (touches.up.isDown && joueur.body.touching.down) {
joueur.setVelocityY(-330);
}
}
On ne déplace jamais le sprite en modifiant directement sa position : on lui donne une vitesse, et le moteur physique s'occupe du reste, image après image. La condition joueur.body.touching.down vérifie que le personnage a bien quelque chose sous les pieds avant de sauter. Retirez-la, et votre héros pourra grimper indéfiniment dans les airs à coups de flèche haut : c'est parfois exactement l'effet recherché, mais autant que ce soit un choix.
Un objectif : ramasser les étoiles et compter les points
Un jeu sans but reste une démonstration technique. Ajoutons douze étoiles qui tombent du ciel, rebondissent sur les plateformes et rapportent des points.
let etoiles;
let score = 0;
let texteScore;
// dans create()
etoiles = this.physics.add.group({
key: 'etoile',
repeat: 11,
setXY: { x: 12, y: 0, stepX: 70 }
});
etoiles.children.iterate((etoile) => {
etoile.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});
this.physics.add.collider(etoiles, plateformes);
this.physics.add.overlap(joueur, etoiles, ramasser, null, this);
texteScore = this.add.text(16, 16, 'Score : 0', {
fontSize: '32px',
color: '#ffffff'
});
function ramasser (joueur, etoile) {
etoile.disableBody(true, true);
score += 10;
texteScore.setText('Score : ' + score);
}
Notez la différence entre collider et overlap. Le premier fait rebondir les objets l'un sur l'autre, le second se contente de signaler qu'ils se touchent, sans les séparer. Une étoile qu'on ramasse ne doit pas repousser le joueur : c'est bien un chevauchement, pas une collision. Le repeat: 11 crée douze étoiles au total — l'originale, plus onze répétitions — espacées de 70 pixels grâce à stepX.
Rechargez la page : le jeu est jouable. Un héros, un décor, des sauts, un score. Le squelette est complet, et tout ce que vous ajouterez ensuite s'appuiera sur ces mêmes briques.
Tester, compiler et mettre en ligne
Pendant le développement, npm run dev recharge le jeu à chaque sauvegarde. Activez debug: true dans la configuration arcade pour afficher les boîtes de collision en vert : c'est le premier réflexe à avoir quand un personnage flotte à trois pixels du sol ou traverse un mur.
Quand le jeu vous convient, npm run build produit un dossier dist/ entièrement statique. Il se dépose tel quel sur GitHub Pages, Netlify, ou dans un sous-dossier de votre propre site. Aucun serveur applicatif, aucune base de données : c'est précisément ce qui rend les jeux HTML5 si commodes à partager.
Et maintenant, dans quelle direction aller ?
La suite logique est d'ajouter un ennemi, un écran de fin, plusieurs niveaux — et surtout de réfléchir à ce qui rend une partie intéressante, ce qui relève moins du code que du game design. Du côté technique, le navigateur d'exemples officiel reste la meilleure documentation qui soit : plusieurs centaines de démonstrations commentées, toutes lisibles dans le navigateur.
Et si vous préférez apprendre loin de l'écran, les ouvrages consacrés au développement de jeux en JavaScript restent un excellent complément, notamment pour les fondamentaux — boucle de jeu, détection de collisions, gestion des états — qui survivent à toutes les versions du moteur.
Votre premier jeu 2D avec Phaser tient en une centaine de lignes. Le deuxième sera plus ambitieux, et c'est bien tout l'intérêt.







0 commentaire