iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
Formations
JavaScript · Débutant

Phaser

Créer un jeu de plateforme complet avec Phaser 4 : scènes, textures générées, tilemap, physique Arcade, animations, ennemis, particules, sons, UI, mobile et déploiement.

Phaser 4JavaScriptViteArcade PhysicsWeb Audio
01Introduction et installation02Scènes, textures générées et menu03Tilemap, niveau et caméra04Le joueur : physique Arcade, clavier et animations05Pièces, pics et ennemis : groupes et collisions06Game feel : particules, événements, caméra et son07Interface, chronomètre, pause et fin de partie08Mobile, build et mise en ligne
Chapitre 3·35 min

Tilemap, niveau et caméra

Un niveau de jeu de plateforme est une grille : chaque case est vide, du sol ou une plateforme. Phaser gère ces grilles avec les tilemaps : une seule texture de tuiles, un tableau d'indices, et Phaser se charge de l'affichage, des collisions et des optimisations. Ce chapitre décrit le niveau dans un fichier texte lisible, le transforme en tilemap et installe une caméra qui défile.

Décrire le niveau en texte

Plutôt qu'un éditeur, on dessine le niveau avec des caractères. Chaque ligne du tableau map est une rangée de tuiles de 32 pixels.

public/levels/level1.json
{
  "nom": "Prairie",
  "temps": 120,
  "map": [
    "............................................................",
    "............................................................",
    "............................................................",
    "............................................................",
    "............................................................",
    "............................................................",
    "...........................................................#",
    ".............................................CC............#",
    "..............CC............................====...........#",
    ".............====.................CC.......................#",
    ".........CC........CC............====......................#",
    "........====......====.................CC..................#",
    "...........................CCC........====.................#",
    "..........................#####............................#",
    "..P.CCC.....S..........^^.#####...S.........S...^.CCC.S..F.#",
    "##################...#################...###################",
    "##################...#################...###################"
  ]
}
CaractèreSignification
.vide
#sol (herbe si la case au-dessus est vide, terre sinon)
=plateforme traversable par le dessous
Pposition de départ du joueur
Cpièce
Sslime
^pics
Fdrapeau d'arrivée

60 colonnes × 17 rangées donnent un niveau de 1920 × 544 pixels, deux fois plus large que l'écran. Modifier le niveau revient à éditer ce fichier et recharger la page : c'est le meilleur moyen de tester des idées de level design en quelques secondes.

La scène de jeu : premier squelette

src/scenes/GameScene.js
import Phaser from 'phaser'
import { TILE } from './BootScene.js'
 
export class GameScene extends Phaser.Scene {
  constructor() {
    super('Game')
  }
 
  init(data) {
    this.niveau = data.niveau ?? 'niveau-1'
    this.fini = false
  }
 
  create() {
    const niveau = this.cache.json.get(this.niveau)
    this.creerDecor(niveau.map)
    this.creerCarte(niveau.map)
    this.cameras.main.fadeIn(300)
  }
}

this.cache.json.get(cle) récupère le JSON chargé par la scène Preload. Les données chargées sont mises en cache pour tout le jeu : pas besoin de les recharger à chaque partie.

Construire la tilemap

src/scenes/GameScene.js
  creerCarte(lignes) {
    // Convertit les caractères du niveau en indices de tuiles (-1 = vide)
    const donnees = lignes.map((ligne, y) =>
      [...ligne].map((c, x) => {
        if (c === '#') return lignes[y - 1]?.[x] === '#' ? 1 : 0
        if (c === '=') return 2
        return -1
      })
    )
 
    this.carte = this.make.tilemap({ data: donnees, tileWidth: TILE, tileHeight: TILE })
    const tileset = this.carte.addTilesetImage('tuiles')
    this.sol = this.carte.createLayer(0, tileset, 0, 0)
 
    this.sol.setCollision([0, 1])
    // Plateformes traversables : collision uniquement par le dessus
    this.sol.forEachTile(tuile => {
      if (tuile.index === 2) tuile.setCollision(false, false, true, false)
    })
  }

Étape par étape :

  1. Conversion en indices. Chaque caractère devient le numéro d'une frame de la texture tuiles créée au chapitre 2. -1 signifie « case vide ». Pour le sol, on regarde la case du dessus : si elle n'est pas du sol, on affiche la tuile avec herbe (0), sinon la terre (1). C'est un autotiling minimaliste : le niveau reste simple à écrire, l'affichage s'adapte.
  2. this.make.tilemap crée une tilemap à partir d'un tableau à deux dimensions.
  3. addTilesetImage('tuiles') associe la texture de tuiles. Phaser la découpe en cases de 32 pixels.
  4. createLayer crée le calque affiché. Une tilemap peut avoir plusieurs calques : décor de fond, sol, premier plan.
  5. setCollision([0, 1]) rend solides les tuiles d'indices 0 et 1.
Début du niveau : sol herbeux, trou, butte et plateformes grises flottantes sous un ciel avec nuages
La tilemap construite à partir du tableau de caractères : sol avec autotiling herbe / terre, plateformes et premier trou.

Plateformes traversables

tuile.setCollision(gauche, droite, haut, bas) choisit les faces qui bloquent. Avec seulement la face du haut active, le joueur traverse la plateforme en sautant par-dessous et atterrit dessus en retombant. C'est le comportement des plateformes dans la plupart des jeux du genre, en deux lignes.

Et l'éditeur Tiled ?

Pour des niveaux plus riches, l'éditeur gratuit Tiled permet de dessiner à la souris, avec plusieurs calques et des objets. Phaser charge directement ses exports :

// preload
this.load.tilemapTiledJSON('niveau-2', 'levels/niveau-2.json')
this.load.image('tuiles-tiled', 'images/tuiles.png')
 
// create
const carte = this.make.tilemap({ key: 'niveau-2' })
const tileset = carte.addTilesetImage('nom-du-tileset-dans-tiled', 'tuiles-tiled')
const sol = carte.createLayer('Sol', tileset)
sol.setCollisionByProperty({ solide: true })

Les objets placés dans Tiled (pièces, ennemis) se récupèrent avec carte.getObjectLayer('Objets').objects. La logique du jeu reste la même que celle de ce cours.

Le décor en parallaxe

Des nuages qui défilent moins vite que le sol donnent une impression de profondeur. C'est l'effet de parallaxe, obtenu avec setScrollFactor :

src/scenes/GameScene.js
  creerDecor(lignes) {
    const largeur = lignes[0].length * TILE
    for (let i = 0; i < 12; i++) {
      const facteur = Phaser.Math.FloatBetween(0.2, 0.5)
      this.add
        .image(Phaser.Math.Between(0, largeur * facteur + 960), Phaser.Math.Between(30, 220), 'nuage')
        .setScrollFactor(facteur)
        .setScale(facteur * 3)
        .setAlpha(0.9)
    }
  }

Un objet avec un scrollFactor de 1 suit la caméra normalement ; à 0, il reste fixe à l'écran (utile pour une interface) ; à 0,3, il se déplace à 30 % de la vitesse de la caméra. Les nuages lointains sont aussi plus petits : taille et vitesse cohérentes renforcent l'illusion.

creerDecor est appelée avant creerCarte : dans Phaser, les objets sont dessinés dans l'ordre de création. Pour forcer un ordre, setDepth(n) place un objet au-dessus de ceux de profondeur inférieure.

Phaser.Math regroupe les utilitaires mathématiques : Between (entier aléatoire), FloatBetween, Clamp, Distance.Between, Angle.Between…

La caméra

Chaque scène possède une caméra principale, this.cameras.main. On la limite au niveau et on lui demande de suivre le joueur :

src/scenes/GameScene.js
  creerCamera() {
    const camera = this.cameras.main
    camera.setBounds(0, 0, this.carte.widthInPixels, this.carte.heightInPixels)
    camera.startFollow(this.joueur, true, 0.12, 0.12)
    camera.setDeadzone(120, 80)
  }
  • setBounds empêche la caméra de montrer ce qui est hors du niveau
  • startFollow(cible, arrondi, lerpX, lerpY) : le lerp à 0,12 fait rattraper la cible en douceur au lieu de la coller rigidement ; arrondi à true évite le flou des sprites en pixel art
  • setDeadzone(120, 80) définit une zone au centre de l'écran dans laquelle le joueur peut bouger sans que la caméra réagisse, ce qui rend le défilement moins nerveux

Le joueur n'existe pas encore : cette méthode sera appelée au chapitre suivant. En attendant, pour explorer le niveau, ajoutez temporairement ce code à la fin de create :

this.cameras.main.setBounds(0, 0, this.carte.widthInPixels, this.carte.heightInPixels)
this.fleches = this.input.keyboard.createCursorKeys()

et cette méthode :

update() {
  if (this.fleches.left.isDown) this.cameras.main.scrollX -= 8
  if (this.fleches.right.isDown) this.cameras.main.scrollX += 8
}
Fin du niveau avec le mur de droite, deux trous et des plateformes
La caméra déplacée à la fin du niveau : le mur de droite et le second trou. Les nuages ont moins défilé que le sol, c'est la parallaxe.

Le mode debug

Ouvrez http://localhost:5173/?debug : grâce à l'option ajoutée dans la configuration, la physique Arcade dessine les corps et les faces de collision. Pour les tuiles, on peut aussi visualiser les collisions avec :

const debug = this.add.graphics().setAlpha(0.6)
this.sol.renderDebug(debug, { tileColor: null, collidingTileColor: new Phaser.Display.Color(243, 134, 48, 200) })

Vous verrez les plateformes traversables marquées seulement sur leur face supérieure.

Niveau avec les tuiles solides colorées en orange par renderDebug
renderDebug colore les tuiles qui ont au moins une face de collision. Les faces actives sont tracées en blanc.

Un tableau de chaînes, une tilemap, un calque avec collisions et une caméra bornée : le monde du jeu existe. Il lui manque un habitant. Le chapitre suivant crée le joueur, avec la physique, le clavier et les animations.

Précédent
Scènes, textures générées et menu
Suivant
Le joueur : physique Arcade, clavier et animations

Développeur fullstack passionné. J'apprends en construisant et je documente tout — front, back, outils. Le code s'apprend mieux en public.

Naviguer

IndexTous les articlesFormationsProfilOutilsBibliothech

Ailleurs

GitHub RSS

Newsletter

Les articles, libs et découvertes. Une fois par semaine, pas plus.

© 2026 William LoreeConçu & codé à la main