CAPITOLO 11
Input Handling
Keyboard
Phaser ci permette in maniera molto agevole di gestire l'input da tastiera attraverso la classe Phaser.Input.Keyboard.
Cursors
Come visto in alcuni esempi precedenti, è possibile gestire il movimento di un personaggio attraverso una classe specifica per i tasti cursore.
Prima definiamo una variabile che ospiterà l'istanza dei tasti cursore:
private _cursors: Phaser.Types.Input.Keyboard.CursorKeys;
Nel metodo create() utilizziamo createCursorKeys() per creare l'istanza:
this._cursors = this.input.keyboard.createCursorKeys();
_cursors fornisce riferimenti alle 4 direzioni (up, down, left, right) e ai tasti space e shift.
Nel metodo update() controlliamo la proprietà isDown per verificare se un tasto è premuto:
if (this._cursors.left.isDown) {
// sposta il personaggio a sinistra
}
if (this._cursors.right.isDown) {
// sposta il personaggio a destra
}
if (this._cursors.up.isDown) {
// salta
}
isDown è true per tutta la durata della pressione del tasto — utile per il movimento continuo del personaggio.
Custom Keys
È possibile gestire l'input con tasti personalizzati diversi dalle frecce direzionali. Definiamo le variabili per ogni tasto:
private _w: Phaser.Input.Keyboard.Key;
private _a: Phaser.Input.Keyboard.Key;
private _s: Phaser.Input.Keyboard.Key;
private _d: Phaser.Input.Keyboard.Key;
private _space: Phaser.Input.Keyboard.Key;
Nel metodo create() utilizziamo addKey() per creare un riferimento a ciascun tasto:
this._w = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
this._a = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
this._s = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
this._d = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
this._space = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
Nel metodo update() controlliamo lo stato del tasto esattamente come per i cursors:
if (this._d.isDown) {
// sposta il personaggio a destra
}
isDown vs JustDown
| Metodo | Comportamento | Uso tipico |
|---|---|---|
isDown | true per tutta la durata della pressione | Movimento del personaggio |
JustDown() | true solo al primo frame della pressione | Sparo, salto, interazione |
Quando vogliamo rilevare una singola pressione (ad esempio per sparare un proiettile), isDown non è efficace perché esegue il codice continuamente. In questi casi usiamo il metodo statico Phaser.Input.Keyboard.JustDown():
// spara un solo proiettile per pressione del tasto
if (Phaser.Input.Keyboard.JustDown(this._space)) {
this.spara();
}
JustDown() rileva la "singola" pressione: il codice viene eseguito una sola volta per ogni pressione del tasto.
Esiste anche Phaser.Input.Keyboard.JustUp() che rileva il rilascio del tasto — utile per caricare colpi o controlli a pressione prolungata.
Un Virtual Joystick
Quando sviluppiamo giochi per dispositivi touch (smartphone e tablet) serve un'alternativa all'input da tastiera. Una soluzione è utilizzare la libreria esterna nipplejs che crea un vero e proprio joystick virtuale.
Installazione
Aggiungere la dipendenza nel file package.json:
"dependencies": {
"nipplejs": "^0.10.1",
"phaser": "^3.9.0"
}
Eseguire nel terminale:
npm update
Importazione
Importare la libreria nella classe del player:
import nipplejs from 'nipplejs';
Implementazione
Nel metodo di inizializzazione del player inseriamo il codice per gestire il movimento tramite virtual joystick:
// creiamo un'istanza del joystick
const joystickManager: nipplejs.JoystickManager = nipplejs.create({
color: 'red'
});
// evento di inizio movimento
joystickManager.on('start', () => {
// il joystick è stato toccato
});
// evento di movimento
joystickManager.on('move', (data: nipplejs.EventData, output: nipplejs.JoystickOutputData) => {
// force: intensità dello spostamento (0-1)
const force: number = Math.min(output.force, 1);
// angle: angolo in radianti
const angle: number = output.angle.radian;
// calcola la velocità in base alla forza e alla velocità massima del player
const speed: number = this._acceleration * force;
// imposta la velocità usando la trigonometria
this.setVelocity(
speed * Math.cos(angle),
speed * Math.sin(angle) * -1
);
});
// evento di fine movimento
joystickManager.on('end', () => {
// il joystick è stato rilasciato — ferma il personaggio
this.setVelocity(0, 0);
});
Il virtual joystick funziona tramite eventi (start, move, end) — non è necessario controllarne lo stato nell'update() come si fa con i tasti della tastiera.
I parametri output.force e output.angle.radian permettono di implementare un movimento analogico: più si sposta il joystick dal centro, maggiore sarà la velocità del personaggio.
Confronto tra i metodi di input
| Metodo | Dispositivo | Quando usarlo |
|---|---|---|
CursorKeys | Tastiera | Prototipazione rapida, movimento 4 direzioni |
Custom Keys (WASD) | Tastiera | Layout alternativo, più tasti contemporanei |
Virtual Joystick | Touch | Mobile e tablet |


L'input è il primo vero "dialogo" tra il giocatore e il tuo gioco — se risponde male, il resto non conta. Per questo vale la pena capire bene la differenza tra isDown e JustDown(): usare il primo dove serve il secondo è l'errore più comune (e più fastidioso da debuggare) quando un personaggio "spara a raffica" senza che tu l'abbia previsto.
Il pattern CursorKeys per il prototipo, Custom Keys per il gioco finito ti fa risparmiare tempo: parti con le frecce per validare velocemente la meccanica, poi passa a WASD (o a un rebind configurabile) quando la UX conta davvero.
Non sottovalutare il virtual joystick: se il tuo gioco gira anche su mobile, è l'unico modo per dare un controllo decente senza tastiera. E il bello è che il codice di movimento resta lo stesso — cambi solo la fonte del segnale (force/angle invece di isDown).
Tip pro: separa sempre la lettura dell'input dalla logica di movimento in due metodi distinti. Così puoi testare (o sostituire) l'input — tastiera, joystick, gamepad — senza toccare una riga della fisica del personaggio. 🎮