Creare un gioco 2D con Phaser 4: la guida passo passo

27 Luglio 2026

phaser

Phaser ha appena tagliato un traguardo atteso da anni: la versione 4 è uscita il 10 aprile 2026, seguita dalla 4.1 a fine mese e dalla 4.2 "Giedi" il 19 giugno. Il motore di rendering è stato riscritto da zero, eppure l'API che migliaia di sviluppatori conoscono a memoria non si è spostata di un millimetro. Tradotto: è il momento giusto per programmare il primo gioco 2D con Phaser, senza il timore di dover reimparare tutto fra sei mesi.

Questa guida parte da zero e arriva a un piccolo gioco davvero giocabile nel browser: un personaggio che corre, salta, atterra sulle piattaforme e raccoglie stelle per fare punti. Mettete in conto un'ora, un editor di codice e un po' di curiosità.

Perché Phaser resta una scelta solida nel 2026

Phaser accompagna gli sviluppatori di giochi HTML5 da più di dieci anni, e il suo punto di forza non è mai stato la promessa di una grafica spettacolare. Semmai il contrario: è un framework sobrio, ben documentato, che gira ovunque ci sia un browser, senza build nativa, senza licenza, senza abbonamento. Un gioco Phaser finito è una manciata di file statici da caricare su un hosting qualunque.

La versione 4 porta una revisione completa del rendering WebGL, ora organizzato in nodi di rendering indipendenti, e unifica gli effetti e le maschere della v3 in un unico sistema di filtri. Sono cambiamenti profondi, ma restano sotto il cofano: sprite, scene, gruppi, fisica arcade, testo e tilemap si scrivono esattamente come prima. Un progetto Phaser 3 si migra di solito in un pomeriggio, e i tutorial esistenti restano validi.

Se preferite vedere prima il minimo indispensabile, il nostro articolo su come programmare un videogioco con Phaser: l'Hello World mette le basi in poche righe. Qui andiamo oltre.

Cosa serve prima di iniziare

Bastano tre cose: Node.js in versione 20 o successiva, un editor di codice e una conoscenza minima del JavaScript moderno — const, funzioni freccia, oggetti letterali. Nessuna nozione di WebGL è necessaria, ci pensa Phaser.

Un dettaglio tecnico va detto subito, perché fa perdere mezz'ora a quasi tutti: un gioco Phaser deve essere servito da un server web, anche in locale. Se aprite index.html con un doppio clic, il browser si rifiuterà di caricare le immagini per motivi di sicurezza e otterrete uno schermo nero, senza alcun messaggio d'errore comprensibile.

Installare Phaser 4 e preparare il progetto

La via più semplice oggi è partire da un progetto Vite, che fornisce il server locale e la compilazione finale senza configurazione:

npm create vite@latest mio-gioco -- --template vanilla
cd mio-gioco
npm install phaser@4.2.0
npm run dev

Create poi una cartella public/assets/ per le immagini. Se non avete ancora grafiche vostre, il pacchetto di esempi ufficiale di Phaser mette a disposizione un cielo, una piattaforma, una stella e un personaggio animato: più che sufficienti per questo tutorial.

Preferite evitare Node? Basta un file HTML e la CDN, a patto di servirlo da un server locale:

<!DOCTYPE html>
<html lang="it">
  <head>
    <meta charset="utf-8">
    <title>Il mio primo gioco</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 configurazione del gioco e la prima scena

Tutto parte da un oggetto di configurazione. Descrive le dimensioni del canvas, il motore di rendering, la gravità del mondo e le scene da caricare. Aprite 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 dice al motore di usare WebGL quando il browser lo permette e di ripiegare sul canvas 2D negli altri casi. La gravità di 300 pixel al secondo quadrato si applica a tutti i corpi dinamici: è lei che riporta a terra il nostro personaggio dopo un salto.

Una scena Phaser poggia su tre funzioni i cui nomi dicono già tutto. preload carica le risorse, create costruisce il mondo una volta che le risorse sono disponibili, e update viene eseguita a ogni fotogramma, sessanta volte al secondo. Questa separazione è la chiave di tutto il resto: nulla va caricato dentro create, nulla va creato dentro update.

Caricare le immagini e costruire lo scenario

Il metodo this.load mette le risorse in coda. Ognuna riceve una chiave, una stringa che riuserete ovunque nel codice:

function preload () {
  this.load.image('cielo', 'assets/sky.png');
  this.load.image('piattaforma', 'assets/platform.png');
  this.load.image('stella', 'assets/star.png');
  this.load.spritesheet('eroe', 'assets/dude.png', {
    frameWidth: 32,
    frameHeight: 48
  });
}

L'ultima riga merita una nota. Uno spritesheet è un'unica immagine che contiene tutte le pose del personaggio affiancate. Dichiarando larghezza e altezza di una cella, si permette a Phaser di ritagliarla automaticamente in fotogrammi numerati, che poi si assemblano in animazioni. Nei progetti più pesanti si passa di solito agli atlas di texture: ne parliamo nella nostra guida completa alla gestione degli asset in Phaser.

Passiamo allo scenario. Le piattaforme non si muovono mai e non subiscono la gravità: sono corpi statici, raccolti in uno staticGroup.

let piattaforme;

function create () {
  this.add.image(400, 300, 'cielo');

  piattaforme = this.physics.add.staticGroup();
  piattaforme.create(400, 568, 'piattaforma').setScale(2).refreshBody();
  piattaforme.create(600, 400, 'piattaforma');
  piattaforme.create(50, 250, 'piattaforma');
  piattaforme.create(750, 220, 'piattaforma');
}

Attenzione a refreshBody(): quando si ridimensiona un corpo statico, il suo riquadro di collisione non segue da solo. Senza questa chiamata il terreno manterrebbe la dimensione originale e l'eroe attraverserebbe allegramente mezzo schermo. È una delle trappole più classiche del motore.

L'eroe, la fisica arcade e le collisioni

Il personaggio, invece, è uno sprite dinamico: cade, rimbalza, reagisce alle collisioni.

let giocatore;

// dentro create()
giocatore = this.physics.add.sprite(100, 450, 'eroe');
giocatore.setBounce(0.2);
giocatore.setCollideWorldBounds(true);

this.physics.add.collider(giocatore, piattaforme);

this.anims.create({
  key: 'sinistra',
  frames: this.anims.generateFrameNumbers('eroe', { start: 0, end: 3 }),
  frameRate: 10,
  repeat: -1
});

this.anims.create({
  key: 'fermo',
  frames: [{ key: 'eroe', frame: 4 }],
  frameRate: 20
});

this.anims.create({
  key: 'destra',
  frames: this.anims.generateFrameNumbers('eroe', { start: 5, end: 8 }),
  frameRate: 10,
  repeat: -1
});

La riga decisiva è this.physics.add.collider(giocatore, piattaforme). Non produce nulla di visibile, ma stabilisce un contratto fra due oggetti: a ogni fotogramma Phaser verifica se si sovrappongono e li separa in modo pulito. Senza di essa l'eroe attraverserebbe lo scenario come un fantasma. Il repeat: -1 delle animazioni significa semplicemente "in ciclo infinito".

Dare il controllo al giocatore

Phaser espone i quattro tasti freccia e la barra spaziatrice in una sola riga:

let tasti;

// dentro create()
tasti = this.input.keyboard.createCursorKeys();

function update () {
  if (tasti.left.isDown) {
    giocatore.setVelocityX(-160);
    giocatore.anims.play('sinistra', true);
  } else if (tasti.right.isDown) {
    giocatore.setVelocityX(160);
    giocatore.anims.play('destra', true);
  } else {
    giocatore.setVelocityX(0);
    giocatore.anims.play('fermo');
  }

  if (tasti.up.isDown && giocatore.body.touching.down) {
    giocatore.setVelocityY(-330);
  }
}

Uno sprite non si sposta mai modificandone direttamente la posizione: gli si assegna una velocità, e al resto pensa il motore fisico, fotogramma dopo fotogramma. La condizione giocatore.body.touching.down verifica che il personaggio abbia davvero qualcosa sotto i piedi prima di saltare. Toglietela, e l'eroe potrà salire all'infinito premendo la freccia in su: a volte è esattamente l'effetto che si cerca, ma è bene che sia una scelta.

Un obiettivo: raccogliere le stelle e contare i punti

Un gioco senza obiettivo resta una dimostrazione tecnica. Aggiungiamo dodici stelle che cadono dal cielo, rimbalzano sulle piattaforme e valgono punti.

let stelle;
let punteggio = 0;
let testoPunteggio;

// dentro create()
stelle = this.physics.add.group({
  key: 'stella',
  repeat: 11,
  setXY: { x: 12, y: 0, stepX: 70 }
});

stelle.children.iterate((stella) => {
  stella.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});

this.physics.add.collider(stelle, piattaforme);
this.physics.add.overlap(giocatore, stelle, raccogli, null, this);

testoPunteggio = this.add.text(16, 16, 'Punti: 0', {
  fontSize: '32px',
  color: '#ffffff'
});

function raccogli (giocatore, stella) {
  stella.disableBody(true, true);
  punteggio += 10;
  testoPunteggio.setText('Punti: ' + punteggio);
}

Notate la differenza fra collider e overlap. Il primo fa rimbalzare gli oggetti l'uno sull'altro, il secondo si limita a segnalare che si stanno toccando, senza separarli. Una stella che si raccoglie non deve respingere il giocatore: è una sovrapposizione, non una collisione. Il repeat: 11 crea dodici stelle in tutto — l'originale più undici ripetizioni — distanziate di 70 pixel grazie a stepX.

Ricaricate la pagina: il gioco è giocabile. Un eroe, uno scenario, i salti, un punteggio. Lo scheletro è completo, e tutto quello che aggiungerete poi si appoggerà su questi stessi mattoni.

Provare, compilare e pubblicare

Durante lo sviluppo, npm run dev ricarica il gioco a ogni salvataggio. Attivate debug: true nella configurazione arcade per disegnare in verde i riquadri di collisione: è il primo riflesso da avere quando un personaggio galleggia tre pixel sopra il terreno o attraversa un muro.

Quando il risultato vi soddisfa, npm run build produce una cartella dist/ completamente statica. Si carica così com'è su GitHub Pages, Netlify o in una sottocartella del vostro sito. Nessun server applicativo, nessun database: è proprio questo che rende i giochi HTML5 così comodi da condividere.

E adesso, in quale direzione andare?

I passi successivi naturali sono un nemico, una schermata finale, più livelli — e soprattutto una riflessione su cosa rende una partita interessante, che riguarda meno il codice e più il game design. Sul piano tecnico, il browser degli esempi ufficiali resta la migliore documentazione possibile: diverse centinaia di dimostrazioni commentate, tutte leggibili direttamente nel browser.

E se preferite studiare lontano dallo schermo, i libri dedicati allo sviluppo di giochi in JavaScript restano un ottimo complemento, soprattutto per i fondamentali — ciclo di gioco, rilevamento delle collisioni, gestione degli stati — che sopravvivono a qualsiasi versione del motore.

Il vostro primo gioco 2D con Phaser sta in un centinaio di righe. Il secondo sarà più ambizioso, ed è proprio questo il bello.

Articoli recenti

Commenti recenti

  1. Massimiliano Ferretti su I Commenti

    Mi permetto di aggiungere una mia considerazione personale che ho riportato dall'utilizzo di C#. Personalmente mi piace commentare funzioni e…

  2. Personalmente ritengo che utilizzare git porti sempre dei vantaggi anche per lo sviluppo solo. Già solo la possibilità di fare…

  3. ciao, il link a discord non è piu valido, vorrei utilizzare il materiale che hai pubblicato tempo fa, come faccio?

"

Itamde è anche una scuola di programmazione online.

Itamde

Impara ciò che desideri, al tuo ritmo

0 Commenti

Invia Un Commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Potrebbe interessarti anche...

Rimani aggiornato sulle ultime notizie e novità

Accedi ai contenuti riservati

Scopri il dietro le quinte dei nostri progetti, risorse esclusive e lo stato di avanzamento delle nostre creazioni in tempo reale.

Iscriviti alla newsletter

Ricevi le nostre notizie, le nostre riflessioni creative e le novità dell'atelier direttamente nella tua casella di posta elettronica.

Seguici

Unisciti alla nostra community sui social network per seguire i nostri progetti quotidiani e interagire con noi.