Phaser 3 Game Tutorial: Your First Playable in a Day

Phaser 3 Game Tutorial: Your First Playable in a Day

Honesty note: this is the tutorial I wish I’d had when I started my game (Merge Fish 2048) — it’s the smallest playable slice: click a fish, it merges, score goes up. No physics, no scene juggling yet — those are the next steps (physics, scenes).

TL;DR

  1. Phaser is a scene → game-object → tween loop: a Phaser.Game with config, scenes containing game objects (sprites/text/images), input on those objects, tweens for movement. You build the smallest version of each and grow (my structure).
  2. One playable in a day is realistic — the loop: create config → one scene → draw something → make it clickable → add a score → add a tween. Each step is ~10 lines.
  3. The three beginner gotchas: (1) this in callbacks — bind or use arrow functions or the emitter’s context; (2) assets won’t load if paths/format are wrong — test with one tiny sprite first (asset pipeline); (3) scene lifecycle — put setup in create(), per-frame logic in update() (scene structure).
  4. Copy-paste the working version below, then break it on purpose — changing values and watching it break is how you learn the API (tween play).

The working example (a click-to-merge slice)

// main.js — the smallest playable
const config = {
  type: Phaser.AUTO,
  width: 800, height: 600,
  scene: { preload, create, update },
  scale: { mode: Phaser.Scale.FIT, autoCenter: Phaser.Scale.CENTER_BOTH }
};

function preload() {
  this.load.image('fish', 'assets/fish.png');   // any sprite
}

function create() {
  this.score = 0;
  const fish = this.add.image(400, 300, 'fish').setInteractive();
  fish.on('pointerdown', () => {
    this.score += 10;
    this.children.getByName('scoreText').setText('Score: ' + this.score);
    this.tweens.add({ targets: fish, scale: 1.3, duration: 120, yoyo: true });
  });
  this.add.text(16, 16, 'Score: 0', { fontSize: '24px' })
    .setName('scoreText');
}

function update() { /* per-frame logic goes here */ }

new Phaser.Game(config);

Run it with a tiny setup: npm create vite → install phaser → replace main.js — the full starter.

The build order (one day, in order)

HourStepWhat you learn
1Config + empty scenePhaser.Game, config object
2Load + display a spritepreload/create, images
3Click it (setInteractive)Input, callbacks, this gotcha
4Score counterState, text objects
5Tween on clickTweens, yoyo
6Grid + merge ruleArrays, game logic (2048 merge)
7Save high scorelocalStorage (save pattern)

Stop there for day one: a playable, scoreable, savable slice is a game you can test — the honest definition of a first milestone.

The three gotchas (read before you type)

  1. this in event callbacks — inside fish.on('pointerdown', function(){...}), this isn’t the scene. Use arrow functions (above) or this-bound handlers. The classic first-day bug.
  2. Asset loading — wrong path or a missing file makes preload fail silently and the scene never starts; console-check and use one small test sprite (pipeline).
  3. create vs update — setup belongs in create() (once), logic in update() (per frame); putting setup in update duplicates objects every frame (scene guide).

Pitfalls

  1. Big scene design on day one — start with one scene and one object; structure grows later.
  2. Physics from hour one — not needed for click-and-merge; add only when movement demands it (physics decision).
  3. Fancy assets first — use a colored square to learn; art later (asset sizes).
  4. Skipping the console — Phaser logs errors clearly; read them, they name the fix.
  5. Copy-paste without breaking — tweak a value, watch it fail, understand why (tween guide).

Bottom line

Your first Phaser 3 game in a day is config → scene → sprite → click → score → tween: the smallest playable slice, in that order, with the three gotchas (this-binding, asset paths, create/update) in mind. Mine started exactly this way and grew one scene at a time (structure) — day one is about a game you can actually test, not a plan you can’t.