Pular para o conteúdo

Phaser Cheat Sheet

Overview

Phaser is a popular open-source HTML5 game framework for creating 2D games that run in web browsers. It provides WebGL and Canvas rendering with automatic fallback, multiple physics engines (Arcade, Matter.js), comprehensive input handling, audio management, sprite animation, tilemap support, and a camera system. Phaser games run on any device with a modern web browser, including desktop, mobile, and tablets, making it one of the most accessible game development frameworks available.

Phaser 3 features a modular architecture where you only include what you need, scene-based game flow management, a powerful data manager, tween animation system, particle effects, and support for texture atlases and sprite sheets. The framework has a vibrant community with extensive documentation, tutorials, and hundreds of examples. It integrates well with modern JavaScript tooling including TypeScript, webpack, and Vite, and can be wrapped in Electron, Cordova, or Capacitor for native distribution.

Installation

# Via npm
npm install phaser

# Create project with Vite template
npm create @phaserjs/game@latest my-game
cd my-game
npm install
npm run dev

# Or manually with Vite
mkdir my-phaser-game && cd my-phaser-game
npm init -y
npm install phaser
npm install -D vite

# CDN (for quick prototyping)
# Add to HTML: <script src="https://cdn.jsdelivr.net/npm/phaser@3/dist/phaser.min.js"></script>

# TypeScript setup
npm install -D typescript @types/phaser
npx tsc --init

Basic Game Setup

import Phaser from 'phaser';

const config = {
    type: Phaser.AUTO,         // WebGL with Canvas fallback
    width: 800,
    height: 600,
    parent: 'game-container',
    backgroundColor: '#2d2d2d',
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 300 },
            debug: false
        }
    },
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

const game = new Phaser.Game(config);

function preload() {
    this.load.image('sky', 'assets/sky.png');
    this.load.image('ground', 'assets/platform.png');
    this.load.spritesheet('player', 'assets/player.png', {
        frameWidth: 32,
        frameHeight: 48
    });
    this.load.audio('jump', 'assets/jump.wav');
}

let player, cursors, platforms, score = 0, scoreText;

function create() {
    this.add.image(400, 300, 'sky');
    
    platforms = this.physics.add.staticGroup();
    platforms.create(400, 568, 'ground').setScale(2).refreshBody();
    
    player = this.physics.add.sprite(100, 450, 'player');
    player.setBounce(0.2);
    player.setCollideWorldBounds(true);
    
    this.physics.add.collider(player, platforms);
    
    cursors = this.input.keyboard.createCursorKeys();
    
    scoreText = this.add.text(16, 16, 'Score: 0', {
        fontSize: '32px',
        fill: '#fff'
    });
}

function update() {
    if (cursors.left.isDown) {
        player.setVelocityX(-160);
        player.anims.play('left', true);
    } else if (cursors.right.isDown) {
        player.setVelocityX(160);
        player.anims.play('right', true);
    } else {
        player.setVelocityX(0);
        player.anims.play('idle', true);
    }
    
    if (cursors.up.isDown && player.body.touching.down) {
        player.setVelocityY(-330);
    }
}

Scene-Based Architecture

class BootScene extends Phaser.Scene {
    constructor() {
        super({ key: 'BootScene' });
    }

    preload() {
        // Load assets
        this.load.image('logo', 'assets/logo.png');
        
        // Progress bar
        const bar = this.add.graphics();
        this.load.on('progress', (value) => {
            bar.clear();
            bar.fillStyle(0xffffff, 1);
            bar.fillRect(200, 290, 400 * value, 20);
        });
    }

    create() {
        this.scene.start('MenuScene');
    }
}

class MenuScene extends Phaser.Scene {
    constructor() {
        super({ key: 'MenuScene' });
    }

    create() {
        const title = this.add.text(400, 200, 'MY GAME', {
            fontSize: '64px',
            fontFamily: 'Arial',
            color: '#ffffff'
        }).setOrigin(0.5);

        const playButton = this.add.text(400, 400, 'PLAY', {
            fontSize: '32px',
            color: '#00ff00'
        }).setOrigin(0.5).setInteractive();

        playButton.on('pointerdown', () => {
            this.scene.start('GameScene');
        });
        
        playButton.on('pointerover', () => {
            playButton.setStyle({ color: '#ff0' });
        });
        playButton.on('pointerout', () => {
            playButton.setStyle({ color: '#0f0' });
        });
    }
}

class GameScene extends Phaser.Scene {
    constructor() {
        super({ key: 'GameScene' });
    }

    init(data) {
        this.level = data.level || 1;
    }

    create() {
        // Game setup
    }

    update(time, delta) {
        // Game loop (delta in ms)
    }
}

// Config with multiple scenes
const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: [BootScene, MenuScene, GameScene]
};

Sprites and Animation

// Create sprite
const player = this.add.sprite(400, 300, 'player');
player.setScale(2);
player.setOrigin(0.5, 1);  // Bottom center
player.setAlpha(0.8);
player.setTint(0xff0000);
player.setFlipX(true);

// Spritesheet animation
this.anims.create({
    key: 'walk',
    frames: this.anims.generateFrameNumbers('player', { start: 0, end: 7 }),
    frameRate: 10,
    repeat: -1  // Loop forever
});

this.anims.create({
    key: 'idle',
    frames: this.anims.generateFrameNumbers('player', { start: 0, end: 3 }),
    frameRate: 5,
    repeat: -1
});

this.anims.create({
    key: 'jump',
    frames: this.anims.generateFrameNumbers('player', { frames: [8, 9, 10] }),
    frameRate: 10,
    repeat: 0
});

player.play('walk');
player.on('animationcomplete', (anim) => {
    if (anim.key === 'jump') player.play('idle');
});

Physics (Arcade)

// Physics sprite
const player = this.physics.add.sprite(100, 400, 'player');
player.setBounce(0.2);
player.setCollideWorldBounds(true);
player.setGravityY(300);
player.setDragX(200);
player.setMaxVelocity(300, 500);

// Static group (platforms)
const platforms = this.physics.add.staticGroup();
platforms.create(400, 568, 'ground');

// Dynamic group (enemies)
const enemies = this.physics.add.group({
    key: 'enemy',
    repeat: 5,
    setXY: { x: 100, y: 0, stepX: 120 }
});
enemies.children.iterate((enemy) => {
    enemy.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});

// Colliders and overlaps
this.physics.add.collider(player, platforms);
this.physics.add.collider(enemies, platforms);
this.physics.add.overlap(player, enemies, hitEnemy, null, this);

function hitEnemy(player, enemy) {
    if (player.body.velocity.y > 0) {
        enemy.destroy();
        score += 10;
    } else {
        player.setTint(0xff0000);
        this.physics.pause();
    }
}

Input Handling

// Keyboard
const cursors = this.input.keyboard.createCursorKeys();
const wasd = this.input.keyboard.addKeys('W,A,S,D');
const spaceKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);

// In update
if (cursors.left.isDown || wasd.A.isDown) { /* move left */ }
if (Phaser.Input.Keyboard.JustDown(spaceKey)) { /* jump once */ }

// Mouse / Touch
this.input.on('pointerdown', (pointer) => {
    console.log(pointer.x, pointer.y);
    if (pointer.leftButtonDown()) { /* shoot */ }
});

// Drag
this.input.setDraggable(sprite);
sprite.on('drag', (pointer, dragX, dragY) => {
    sprite.x = dragX;
    sprite.y = dragY;
});

// Gamepad
this.input.gamepad.once('connected', (pad) => {
    pad.on('down', (index, value, button) => {
        if (index === 0) player.jump();
    });
});

Camera

// Follow player
this.cameras.main.startFollow(player, true, 0.05, 0.05);
this.cameras.main.setZoom(1.5);
this.cameras.main.setBounds(0, 0, 3200, 600);

// Camera effects
this.cameras.main.shake(200, 0.01);
this.cameras.main.flash(500, 255, 0, 0);
this.cameras.main.fade(1000, 0, 0, 0);

// Deadzone
this.cameras.main.setDeadzone(200, 100);

Tweens

// Basic tween
this.tweens.add({
    targets: sprite,
    x: 600,
    y: 300,
    duration: 2000,
    ease: 'Power2',
    yoyo: true,
    repeat: -1
});

// Scale bounce
this.tweens.add({
    targets: button,
    scaleX: 1.2,
    scaleY: 1.2,
    duration: 100,
    yoyo: true,
    ease: 'Quad.easeInOut'
});

// Timeline
const timeline = this.tweens.createTimeline();
timeline.add({ targets: sprite, x: 600, duration: 1000 });
timeline.add({ targets: sprite, y: 400, duration: 500 });
timeline.add({ targets: sprite, alpha: 0, duration: 300 });
timeline.play();

Tilemaps

// Load in preload
this.load.tilemapTiledJSON('level1', 'assets/maps/level1.json');
this.load.image('tiles', 'assets/tilesets/tileset.png');

// Create in create
const map = this.make.tilemap({ key: 'level1' });
const tileset = map.addTilesetImage('tileset-name', 'tiles');
const backgroundLayer = map.createLayer('Background', tileset, 0, 0);
const groundLayer = map.createLayer('Ground', tileset, 0, 0);

// Set collision
groundLayer.setCollisionByProperty({ collides: true });
// Or by tile index
groundLayer.setCollisionBetween(1, 50);

this.physics.add.collider(player, groundLayer);

// World bounds from map
this.physics.world.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);

Configuration

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scale: {
        mode: Phaser.Scale.FIT,
        autoCenter: Phaser.Scale.CENTER_BOTH,
        parent: 'game-container'
    },
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 300 },
            debug: process.env.NODE_ENV === 'development'
        }
    },
    render: {
        pixelArt: true,           // No anti-aliasing for pixel art
        antialias: false,
        roundPixels: true
    },
    audio: {
        disableWebAudio: false
    },
    scene: [BootScene, MenuScene, GameScene],
    fps: {
        target: 60,
        forceSetTimeOut: false
    }
};

Advanced Usage

// Particle emitter
const particles = this.add.particles(400, 300, 'particle', {
    speed: { min: 100, max: 200 },
    angle: { min: 0, max: 360 },
    scale: { start: 1, end: 0 },
    lifespan: 1000,
    gravityY: 200,
    quantity: 2,
    frequency: 50
});

// Follow a sprite
particles.startFollow(player);

// Groups with recycling
const bulletGroup = this.physics.add.group({
    classType: Bullet,
    maxSize: 30,
    runChildUpdate: true
});

function fireBullet() {
    const bullet = bulletGroup.get(player.x, player.y);
    if (bullet) {
        bullet.fire(player.x, player.y, target.x, target.y);
    }
}

// Data manager for persistence
this.registry.set('score', 0);
this.registry.set('lives', 3);
const score = this.registry.get('score');
this.registry.events.on('changedata-score', (parent, value) => {
    scoreText.setText(`Score: ${value}`);
});

// Timer events
this.time.addEvent({
    delay: 1000,
    callback: spawnEnemy,
    callbackScope: this,
    loop: true
});

Troubleshooting

IssueSolution
Black screenCheck asset paths are correct; look for console errors
Blurry pixel artSet pixelArt: true and roundPixels: true in config
Physics bodies misalignedUse setOrigin() consistently; enable debug to visualize bodies
Game runs slow on mobileReduce particle count; use texture atlases; limit physics bodies
Audio not playing on mobilePlay audio on first user interaction (tap); use this.sound.unlock()
Assets not loadingCheck file paths relative to index.html; use devtools network tab
Scene not switchingVerify scene key matches; check this.scene.start() is called
Tilemap not renderingEnsure tileset name in JSON matches addTilesetImage first parameter
Input not workingCheck scene is active; verify input processor is not blocked
Memory leaksDestroy sprites/groups in scene shutdown; use object pooling