Skip to content

Instantly share code, notes, and snippets.

@louisho5
Forked from woubuc/phaser-cheatsheet.md
Last active July 31, 2025 10:26
Show Gist options
  • Save louisho5/d6318b784c9bf280f15385d144dbda58 to your computer and use it in GitHub Desktop.
Save louisho5/d6318b784c9bf280f15385d144dbda58 to your computer and use it in GitHub Desktop.

Phaser 3 Cheatsheet

Originally inspired by woubuc/phaser-cheatsheet.md, this version has been almost completely rewritten and expanded with new notes and insights to better support everyone learning and using Phaser 3.

Starting a new game

All config is optional, but width, height and scene are recommended to add.

let config = {
    type: Phaser.AUTO,
    width: 1200,
    height: 800,
    scene: [
        GameScene, EndScene
    ],
    parent: 'game-wrapper',  //<div id="game-wrapper"></div>
    physics: {
        default: 'arcade',
        arcade: {
            debug: true,
            gravity: { y: 50 }
        }
    },
    scale: {
        mode: Phaser.Scale.FIT,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    backgroundColor: '#000000',  //Set canvas background
    transparent: true,    //Set canvas to transparent
    pixelArt: true,  //If required to build a pixel art game
    banner: false,  // Disables the Phaser banner from console
};

let game = new Phaser.Game(config);

Creating a game state object

class GameScene extends Phaser.Scene {

    constructor() {
        super({key: 'GameScene', active: true});      
        // In PauseScene should be:  {key: 'PauseScene', active: false}
    },
    
    init(data) { 
        // init() is not necessary
        // Get the passed data from other scene
    }

    preload() {
        // Assets to be loaded before create() is called
    },

    create() {
        // Adding sprites, sounds, etc...
        this.customFunc();  //Try customFunc.call(this) when this.func() not working
    },

    update() {
        // Keep update on everytick
        // Game logic, collision, movement, etc...
    }

    customFunc() {
      // Create your custom function
    }

}

Working with globals

Reference: https://www.stephengarside.co.uk/blog/phaser-3-custom-config-global-letiables/

let config = {
    type: Phaser.AUTO,
    width: 400,
    height: 300,
    ~~myCustomProperty: null,~~  // No need to set here
};
let game = new Phaser.Game(config);
game.config.myCustomProperty = true;  //Just set in here

console.log(game.config.myCustomProperty);

Fullscreen

Reference: https://docs.phaser.io/phaser/concepts/scale-manager#full-screen

// Enter full screen mode
scene.scale.startFullscreen();

// Exit full screen mode
scene.scale.stopFullscreen();

// Toggle full screen mode
scene.scale.toggleFullscreen();

// Check if current game is fullscreen mode
let isFullscreen = scene.scale.isFullscreen;

Basic Usage

Loading an image/music/asset

preload(){
    /* Optional: set a custom path */
    this.load.path = 'assets/images/';

    this.load.image('background', 'background.png');
    this.load.audio("bgm",  ["bgm.mp3"]);
    this.load.spritesheet("guy",  "guy-walk.png",  { frameWidth: 50, frameHeight: 50 });

    /* Preloading */
    this.load.on('progress', function (value) {
        console.log(`Loading: ${parseInt(value*100)}%`);
    });

    /* Preloading (With loading bar) */
    let progressX = this.game.config.width / 2;
    let progressY = this.game.config.height / 2;
    let progressWidth = this.game.config.width * 0.8;
    let progressHeight = 30;
    let progressBox = this.add.rectangle(progressX, progressY, progressWidth, progressHeight, 0xffffff, 0.5).setOrigin(0.5, 0.5);
    let progressBar = this.add.rectangle(progressX, progressY, progressWidth, progressHeight, 0x00A758, 1).setOrigin(0.5, 0.5);
    
    this.load.on('progress', function (value) {
        progressBar.width = progressWidth * value;
    });
    this.load.on('complete', function (value) {
        progressBar.destroy();
        progressBox.destroy();
    });
}

Adding an image

Static image

preload() {
    this.load.image('background', 'background.png');
    this.load.image('background_new', 'background_new.png');
create() {
    this.background = this.add.image(x, y, 'background');
    
    // Change the texture
    this.background.setTexture('background_new');
}

SVG

preload() {
    this.load.svg('fireflower', 'https://cdn.phaserfiles.com/v355/assets/svg/fireflower.svg')
}
create() {
    this.add.image(150, 150, 'fireflower').setScale(0.3).setOrigin(0);
}

Adding tileSprite / looping background

create() {
    this.background = this.add.tileSprite(0, 0, game.config.width, game.config.height, 'background').setOrigin(0, 0);
}
update() {
    this.background.tilePositionX -= 1;
}

Adding text

Reference: https://rexrainbow.github.io/phaser3-rex-notes/docs/site/text/#add-text-object

function create() {
    //Assigned for later use
    this.label = this.add.text(x, y, "John Doe", {
        fontSize: '12px',
        fontFamily: 'Arial, Sans-serif',
        color: '#CE721C',
        backgroundColor: '#F8D38A',
        padding: { left: 10, right: 50, top: 5, bottom: 5 },
        stroke: '#000',
        strokeThickness: 5,
        align: 'center',
        lineSpacing: 20,  //line-height
        wordWrap: { width: 450, useAdvancedWrap: true },
        shadowColor: '#000',
        shadowOffset: { x: 10, y: 10 },
        shadowBlur: 5,
    });
    this.label.text = "I'm changing the text \n inside the label letiable!";
    
    //Set text with multiple lines no need "\n'
    this.label.setText([
        `Correct: ${this.correct}`,
        `Wrong: ${this.wrong}`,
        `Score: ${this.score}`,
    ]);

    //Set styles
    this.label.setShadow(3, 3, 'rgba(0,0,0,0.5)', 2);

    //Set letter spacing in 5px
    this.label.setLetterSpacing(5);

    //Word wrap when greater than 100px width
    this.label.setWordWrapWidth(100, false);
    
    //Set Origin
    this.label.setOrigin(1, 0);
    
    //Set Depth (z-index)
    this.label.setDepth(1);
    
    //Set visibility
    this.label.setVisible(false);
    
    //Center the text
    let screenCenterX = this.cameras.main.worldView.x + this.cameras.main.width / 2;
    let screenCenterY = this.cameras.main.worldView.y + this.cameras.main.height / 2;
    this.txt = this.add.text(screenCenterX, screenCenterY, "My Text").setOrigin(0.5);
}

Adding Custom Font

Method 1 - Works with Phaser v3.87 or later

preload() {
    this.load.font('Lato', 'assets/fonts/Lato.otf', 'opentype');
    this.load.font('Roboto', 'assets/fonts/Roboto.ttf', 'truetype');
}

create() {
    this.add.text(0, 0, 'Your Font Here', { 
        fontFamily: 'Lato',
        fontSize: '32px',
    });
    this.add.text(0, 80, 'Your Font Here', { 
        fontFamily: 'Roboto',
        fontSize: 32,
    });
}

Method 2 - (Legacy)

/* style.css */
@font-face {
    font-family: "Roboto";
    src: url('../font/Roboto.ttf');
}
/* HTML */
<div style="position:absolute; left:-1000px; visibility:hidden;">
    <div style="font-family:Roboto">.</div>
    <div style="font-family:Montserrat">.</div>
</div>
this.add.text(0, 0, "Your Text Here", {
    fontFamily: 'Roboto'
});

Adding spritesheet animation

Load with PNG spritesheet (Recommend) - Example 1, Example 2

preload() {
    this.load.spritesheet("guy", "guy-walk.png", {
      frameWidth: 50,
      frameHeight: 50
    });
}
create() {
    this.anims.create({
      key: "guyWalking",
      frames: this.anims.generateFrameNumbers("guy", { frames: [ 0, 1, 2, 3 ] }),
//      frames: this.anims.generateFrameNumbers("guy", {
//            start: 0,
//            end: 8
//      }),
      frameRate: 12,
      repeat: -1
    });
    this.player = this.add.sprite(x, y, "guy");
    this.player.play("guyWalking");
    this.player.body.setSize(40, 40);  // for better size adjustment (remove space)
    this.player.body.setOffset(5, 5);  // for better size adjustment (remove space)
}

Load with PNG sequence - Example

preload() {
    /* Preload all image sequences */
    this.load.image('explosion1', 'explosion1.png');
    this.load.image('explosion2', 'explosion2.png');
    this.load.image('explosion3', 'explosion3.png');
}
create() {
    /* Create animation with all image sequences */
    this.anims.create({
        key: 'explosion',
        frames: [
            { key: 'explosion1' },
            { key: 'explosion2' },
            { key: 'explosion3', duration: 50 }   // You can set duration for each frame
        ],
        frameRate: 8,
        repeat: 1
    });
    /* Create object and play animation */
    this.explosion = this.add.sprite(0, 0, 'explosion1');
    this.explosion.play('explosion');
    //Pause
    this.explosion.anims.pause();
}

Add animation with atlas - Generator

preload() {
    // Load the texture atlas
    this.load.atlas('myAtlas', 'atlas.png', 'atlas.json');
}

create() {
    // Apply animation from the atlas
    const animationConfig = {
        key: 'walking',
        frames: this.anims.generateFrameNames('myAtlas', {
            prefix: 'walking_',
            start: 0,
            end: 5,
            zeroPad: 2
        }),
        frameRate: 10,
        repeat: -1
    };

    this.anims.create(animationConfig);

    this.player = this.physics.add.sprite(400, 300, 'myAtlas', 'walking_00');
    this.player.anims.play('walking');
}

Basic Styles

Set Alpha(opacity) & Visible

this.player.visible = false;
this.player.alpha = 0.5;

Change z-index / Bring to front

Reference: https://phaser.io/examples/v3/view/depth-sorting/z-index

/* Bring object to front */
this.player.setDepth(1);

Transform Objects

Objects origin (anchor)

Reference: https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Components.Origin.html

//Objects have an origin property that goes from 0 (top left) to 1 (bottom right)
//It is default in centerX(0.5) centerY(0.5)
image.originX = 0.2;
image.originY = 1;

//This sets it in the 0
image.setOrigin(0, 0);

Scaling an object

//Objects have a scale property that defaults to 1
//Negative values essentially mirror it on the affected axis
image.setScale(1.2, 1.2)

Rotate an object

//Objects rotation defaults is 0, but you can use Math to convert from degree
image.rotation = 0;
image.rotation = Phaser.Math.DegToRad(90);

Flipping an object

Reference: https://phasergames.com/how-to-flip-a-sprite-in-phaser-3/

let duck1 = this.add.image(150, 150, "duck");
let duck2 = this.add.image(350, 150, "duck");

duck2.flipX = true;

gameObject.setFlip(true, false);
gameObject.toggleFlipX();
gameObject.toggleFlipY();
gameObject.resetFlip();

Animations

Tweening

You may learn about the Ease functions ****such as "Bounce", "Back", "Power3"

// Adding an example sprite but you can tween pretty much anything
this.player = game.add.sprite(100, 100, 'player');

this.tweens.add({
    targets: this.player,
    x: 200,
    y: 200,
    scaleX: 0.8,
    scaleY: 0.8,
    //alpha: { from: 0, to: 1 },  //Use from to
    alpha: Phaser.Math.FloatBetween(0, 1),
    duration: Phaser.Math.Between(1500, 3000),
    ease: 'Sine.easeInOut',
    //repeat: 0,  // -1=infinity; 0=no loop; 1=loop once; 2=loop twice...
    //repeatDelay: 0, // Add delay between repeats
    //yoyo: true,
    //paused: true
});

// Tween for multiple objects
this.tweens.add({
    targets: [this.player, this.enemies, this.boss],
    alpha: 0,
    duration: 1500,
});

Create a chain animation

// Create Chain
let myAnimation = this.tweens.chain({
    targets: this.player,
    tweens: [
        {
            angle: 0,
            scale: 0.5,
            duration: 500,
            onStart() { console.log('start 1')},
            onComplete() { console.log('complete 1')}
        },
        {
            angle: 360,
            scale: 1,
            ease: 'Power2',
            duration: 500,
            onStart() { console.log('start 2')},
            onComplete() { console.log('complete 2')}
        }
    ],
    repeat: -1,  // Set -1 for infinite loop
    delay: 5000  // Start animation after 5 seconds
});
myAnimation.stop();  // Stop the animation

Create a Timeline

// Create Timeline
let timeline = this.add.timeline([
    {
        at: 0,  // At 0 second
        tween: {
            targets: this.player,
            y: 400,
            duration: 2000,
        }
    },
    {
        at: 2500,  // At 2.5 seconds
        run() {
            this.player.setScale(1.5);
        }
    },
]);
timeline.play();  // Start playing the animation
timeline.repeat().play();  // Play with repeat (loop)
timeline.repeat(false);  // Stop repeat

// Create Timeline (Version 2)
let timeline = this.add.timeline();
timeline.add({
    targets: this.player,
    y: 400,
    duration: 300,
    ease: 'Linear',
    onComplete: () => { },
});

Number animation example

let scoreText = this.add.text(400, 300, '0', { 
    fontSize: '32px', 
    color: '#ffffff',
});

this.tweens.addCounter({
    from: 0,
    to: 1200,
    duration: 3000,
    ease: 'Cubic.easeOut',
    onUpdate: (tween) => {
        const value = Math.round(tween.getValue());
        //scoreText.setText(value);
        scoreText.setText(value.toLocaleString('en-US'));
    }
});

Use of shader (preFX / postFX)

Examples - Online Notes

/* NOTES: preFX only works with sprite */
this.player= this.add.sprite(0, 0, 'player')

this.player.preFX.addShine(
    0.5,    // speed
    0.5,    // gradient position (0-1)
    0.7,    // width of the shine
    0.6     // alpha
);

this.player.preFX.addBlur(
    4,      // blur quality (1-8)
    2.0     // blur strength
);

this.player.preFX.addBloom(
    0xff0000,   // color
    4,          // outerStrength
    0,          // innerStrength
    false       // knockout (Hide object but show only style)
);

this.player.preFX.addGlow(
    0xff0000,   // color
    0,          // offset x
    0,          // offset y
    2,          // distance/strength
    1,          // alpha
    16          // quality (steps)
);

this.player.preFX.addShadow(
    1,          // x offset power, color, samples, intensity
    1,          // y offset
    0.1,        // decay (blur amount)
    1,        // power
    0x000000,   // color
    12,          // sample steps (quality)
    1,          //intensity
);
this.player.preFX.addPixelate(
    4           // amount (pixel size, higher = more pixelated)
);
this.player.preFX.addVignette(
    0.5,        // x (horizontal position, 0-1)
    0.5,        // y (vertical position, 0-1)
    0.7,        // radius (size of the clear center area)
    0.5,        // strength (intensity of the effect)
    0x000000    // color of the vignette
);

this.player.preFX.addGradient(
    0xff0000,   // color1
    0x00ff00,   // color2
    1,          // alpha
    0,          // fromX
    0,          // fromY
    200,        // toX
    200,        // toY
    0,          // size (Low value would be smoother)
);

this.player.preFX.addCircle(
    0.5,      // x (horizontal position, 0-1)
    0.5,      // y (vertical position, 0-1)
    0.5,      // radius
    0x000000, // color (outside circle)
    0         // alpha (0 = transparent, 1 = opaque)
);

this.player.preFX.addBokeh(
    3,        // radius
    1,        // amount
    0.1,      // blend (0-1)
    0xffffff  // color
);

Tweening the effects

create() {
    let glowFX = this.player.preFX.addGlow();
    //glowFX.setActive(false);
    //glowFX.setActive(true);
    glowFX.outerStrength = 8;
    glowFX.innerStrength = 8;

    this.tweens.add({    // you may also tween the glow effects
        targets: glowFX,
        outerStrength: 16,
        innerStrength: 16,
        ease: 'Sine.easeInOut',
        repeat: -1,
        yoyo: true,
        duration: 1500,
    });
}

Displacement map

preload() {
    // Load your displacement map (usually a black and white texture)
    this.load.image('displacement', 'displacement_map.png');
    this.load.image('background', 'background.png');
}

create() {
    const image = this.add.image(400, 300, 'background');

    // Add displacement effect
    const fx = image.preFX.addDisplacement(
        'displacement',   // displacement map key
        2.0,              // intensity x
        2.0               // intensity y
    );

    this.tweens.add({     // Animate the displacement
        targets: fx,
        x: 100,           // offset x
        y: 100,           // offset y
        duration: 2000,
        yoyo: true,
        repeat: -1
    });
}

Particles effects

preload() {
    this.load.image('bg', 'flares.png');
}
create() {
    let emitter = this.add.particles(300, 200, 'flares', {
        frame: 'white',
        blendMode: 'ADD',
        lifespan: 1200,
        gravityY: -100,
        scale: { start: 0.3, end: 0 },
        emitting: false
    });
    emitter.start();
    emitter.addEmitZone({ source: new Phaser.Geom.Circle(0, -20, 90) });
}

Use Case (Play once only)

preload () {
    this.load.image('particle', 'assets/img/particle_shape.png');
}
create () {
    const particles = this.add.particles(100, 100, 'particle', {
        speed: { min: 100, max: 200 },
        angle: { min: 0, max: 360 },
        scale: { start: 1.5, end: 0 },
        blendMode: 'NORMAL',
        lifespan: 500,
        gravityY: 50,
        quantity: 2,
    });

    // Stop emitting after 100ms
    this.time.delayedCall(100, () => {
        particles.stop();
    });

    // Destroy the particle system after 2 seconds
    this.time.delayedCall(2000, () => {
        particles.destroy();
    });
}

Sounds

Playing music

preload() {
    this.bgm = this.load.audio("bgm",  ["bgm.mp3"]);
}
create() {
    // Assign it so we can reference it
    this.bgm = this.sound.add("bgm", { loop: false });
    this.bgm.loop = true;
    this.bgm.play();
}

Muted Sounds

create() {
    // Mute all sounds
    this.game.sound.mute = true;

    // Set volumn of a soundtrack
    this.bgm.volume = 0.5;
}

User Inputs

Set custom cursor

create(){
    this.input.setDefaultCursor('url(img/cursor.cur), pointer');
}

Mouse & touch input

create(){

    /* Set Multitouch limits (default: 1) */
    this.input.addPointer(3);  //3 multitouch

    /* Onclick event */
    this.player.setInteractive();
    this.player.on('pointerup', function(){
        console.log('Clicked');
    });

    /* Disable events */
    this.player.disableInteractive();

    /* Custom clickable area */
    this.player.setInteractive({
        hitArea: new Phaser.Geom.Rectangle(-50, -60, 220, 360),
        hitAreaCallback: Phaser.Geom.Rectangle.Contains,
        useHandCursor: true,
    });

    /* All other input properties */
    this.player.setInteractive({
        draggable: true,
        cursor: 'pointer',
        pixelPerfect: true,
        useHandCursor: true,
        hitArea: new Phaser.Geom.Rectangle(0, 0, 100, 100),
        dragStartCallback: function() {
            // Code to execute when drag starts
        },
        dragEndCallback: function() {
            // Code to execute when drag ends
        }
    });
}

Example of Drag and Drop

create(){
    const button = this.add.image(200, 100, 'button');
    button.setInteractive({ draggable: true })

    button.on('dragstart', function (pointer) {
        this.setTint(0xc1c1c1);
    });
    button.on('drag', function (pointer, dragX, dragY) {
        console.log('drag', dragX, dragY)
        this.x = dragX;
        this.y = dragY;
    });
    button.on('dragend', function (pointer) {
        this.clearTint();
    });
}

Keyboard input

create() {
    /* Onclick event */
    this.keyboard = this.input.keyboard.createCursorKeys();
}
update() {
    if(this.keyboard.left.isDown){
        this.player.x += -2;
    }
    if(this.keyboard.right.isDown){
        this.player.x += 2;
    }
    if(this.keyboard.up.isDown){
        this.player.y += -2;
    }
    if(this.keyboard.down.isDown){
        this.player.y += 2;
    }
}
/* Logic */
this.input.keyboard.on('keydown-W', () => {
     // Event listener pattern: "keydown + {KEY}"
});

/* Example */
this.input.keyboard.on('keydown-SPACE', () => {
     // Space key-down events
});

this.input.keyboard.on('keyup-SPACE', () => {
     // Space key-up events
});

Add HTML into the game

Adding DOM Elements - Demo

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'game-wrapper',   // Must have a parent
    dom: {                    // Enable DOM plugin
        createContainer: true
    },
    scene: MainScene
};

// How to use
create() {
    let heading = this.add.dom(400, 300).createFromHTML(`<h1 style="background-color: lightblue;">Hello, World!</h1>`);
    
    heading.addListener('click');
    heading.on('click', () => {
        alert('DOM H1 clicked!');
    });
}

Time Events

Set time events

/* Similar to setTimeOut() */
this.time.addEvent({
    delay: 3000,
    loop: false,
    callback: function() {
        console.log('function run after 3 seconds');
    },
    callbackScope: this
});

/* Similar to setInterval() */
this.time.addEvent({
    delay: 1000,
    loop: true,
    callback: function() {
        console.log('Keep looping on every seconds');
    },
    callbackScope: this
});

Managing game timer

let timerCountdown = 60;
let myTimer = this.time.addEvent({
    delay: 1000,
    loop: true,
    callback: function() {
  timerCountdown -= 1;
  console.log(timerCountdown);
    },
});

/* Use of delay */
this.time.delayedCall(60*1000, function() {
    myTimer.remove();
    console.log('Timeout');
});

Generating random numbers

Reference: https://rexrainbow.github.io/phaser3-rex-notes/docs/site/random/

//Random integer
let value = Phaser.Math.Between(min, max);
//Random floating point number
let value = Phaser.Math.FloatBetween(min, max);

Working with container (group)

Reference: https://rexrainbow.github.io/phaser3-rex-notes/docs/site/containerlite/

/*** Default container ***/
this.add.container(x, y, [this.player, this.name]);

//Create a container
let container = this.add.container(300, 300);

//Add game object
container.add(this.player);

//Remove game object
container.remove(this.player);

/*** Advanced container plugin ***/
preload() {
    this.load.plugin('rexcontainerliteplugin', '<https://cdn.jsdelivr.net/gh/rexrainbow/phaser3-rex-notes@latest/dist/rexcontainerliteplugin.min.js>', true);
}
create() {
    let container = this.add.rexContainerLite(300, 300);
    container.setOrigin(0.5, 0.5); //only work with plugin
}

Adding camera to sprites

Reference: https://photonstorm.github.io/phaser3-docs/Phaser.Cameras.Scene2D.CameraManager.html

create() {
  // Set background color
  this.cameras.main.setBackgroundColor('#000000');

  // Set boundary so that it would hide the black background
  this.cameras.main.setBounds(0, 0, 800, 600);

  // Add camera(s)
  this.camera1 = this.cameras.main.setSize(400, 600);
  this.camera2 = this.cameras.add(400, 0, 400, 600);  // splitscreen

  // Start follow camera
  this.camera1.startFollow(this.player1);
  this.camera2.startFollow(this.player2);
  this.camera2.setFollowOffset(-100, 0); //(x,y)

  // Stop follow camera
  this.camera1.stopFollow();

  // Set attributes
  this.camera1.zoom = 1.5; // 1=no zoom, >1=zoom in, <1=zoom our
  this.camera1.x = 300;
  this.camera1.centerOn(0, 0);  //center x,y as coordinate instead of left top x,y

  // Camera animation
  this.camera1.pan(300, 300, 2000, 'Sine.easeInOut');
  this.camera1.zoomTo(1.5, 3000, 'Sine.easeInOut');
}

Camera Effects

create() {
  // Shaking effects
  this.cameras.main.shake(200, 0.01);  // (duration, intensity)
  
  // Fade in/out effects
  this.cameras.main.fadeOut(1000, 0, 0, 0);  // Black fade out
  this.cameras.main.fadeIn(1000, 0, 0, 0);   // Fade in from black
  
  // Flash effects
  this.cameras.main.flash(500);  // (duration)
  
  // Zoom effects
  this.cameras.main.zoomTo(1.25, 1500);  // (zoom level, duration)
  
  // Pan effects
  this.cameras.main.pan(500, 500, 1500, 'Sine.easeInOut');  // (x, y, duration, ease)
  
  this.cameras.main.rotateTo(Math.PI, false, 1000, 'Power2');  // (180 degrees, shortestPath(auto-nearest), duration, ease)
  
  // Make camera follow a game object
  this.cameras.main.startFollow(player, true);
  this.cameras.main.startFollow(player, true, 0.1, 0.1);  // Smooth following
  this.cameras.main.stopFollow();
}

Use Case 1 - Following the Player

create() {
    this.player = this.physics.add.sprite(0, 0, 'block');
    this.player.setCollideWorldBounds(true);
    this.cameras.main.startFollow(this.player);
    this.cameras.main.setFollowOffset(0, 0);  // 0,0 refers to center screen
    this.cameras.main.setBounds(0, 0, 1920*2, 1080*2);
    this.physics.world.setBounds(0, 0, 1920*2, 1080*2);
}

Managing game scene

Reference: https://rexrainbow.github.io/phaser3-rex-notes/docs/site/scenemanager/

// Move to "SceneB"
this.scene.start('SceneB');

Pause Game with popup box

// Include PauseScene in the scenes
const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: [GameScene, PauseScene]
};

// In 'MainScene'
this.scene.pause().launch('PauseScene');
//game.scene.pause('GameScene').launch('PauseScene');  // alternative

// In 'PauseScene'
this.scene.stop().resume('GameScene');
//game.scene.stop('PauseScene').resume('GameScene');  // alternative

In pauseScene.js

class PauseScene extends Phaser.Scene {

    constructor(){
        super({ key: 'PauseScene', active: false });
    }

    create(){
        let _this = this;

        // Add a background rectangle to cover the screen
        this.background = this.add.rectangle(0, 0, this.game.config.width, this.game.config.height, '0x000000', 0.8).setOrigin(0);
        background.setInteractive();  //to disable click events from the GameScene

        // Add a "Resume" button
        this.btnResume = this.add.text(400, 300, 'Resume', { fontSize: '32px', fill: '#fff' }).setOrigin(0.5);
        this.btnResume.setInteractive();
        this.btnResume.on('pointerup', function(){
            _this.scene.stop().resume('GameScene');
        });
    }

}

Scene transition effects

this.input.keyboard.once('keydown-SPACE', () => {
    this.cameras.main.fadeOut(1000, 0, 0, 0);  // fade to black
});

this.cameras.main.once(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, (cam, effect) => {
    this.scene.start('MainScene');
});

Data from other scenes

Method 1

// In 'MainScene'
this.myValue = 0;

// From 'OtherScene'
this.scene.get('MainScene').myValue;

Method 2

// In 'MainScene'
this.scene.launch('OtherScene', { 
    mainScene: this,     // pass current scene
    myValue: myValue,    // pass other values
});

// From 'OtherScene'
init(data) {
    this.mainScene = data.mainScene;   // get previous scene
    this.myValue = data.myValue;        // get other passed values
}
create() { ... }

Perform a action/events

let btn_close = this.add.image(0, 0, 'btn_close');

//Perform a button click
btn_close.emit('pointerup', { x: btn_close.x, y: btn_close.y });

Arcade Physics 2D

Collider (Overlap)

// Create arcade sprite
this.player = this.physics.add.sprite(300, 630, 'player');
this.player.body.setSize(40, 40);  // for better size adjustment (remove space)
this.player.body.setOffset(5, 5);  // for better size adjustment (remove space)
this.player.setCollideWorldBounds(true);  // always inside screen
this.player.setBounce(0);  // set rebouncing force

// Get the player body attributes
let velocityX = this.player.body.velocity.x;

// Create some static sprite (Won't apply the gravity and velocity)
this.coin = this.physics.add.staticSprite(390, 500, 'coin');  // set immovable object
// Or same with above
this.coin = this.physics.add.sprite(390, 500, 'coin');
coin.body.setImmovable(true);
coin.body.allowGravity = false;

// Create platforms
this.platforms = this.physics.add.staticGroup();
this.ground = this.platforms.create(x, y, 'ground');
this.ground.setOrigin(0, 0);
this.ground.refreshBody();
// Set custom collision directions
this.ground.body.checkCollision.left = false;
this.ground.body.checkCollision.right = false;
this.ground.body.checkCollision.up = true;  // Just make top collision work, jump over it
this.ground.body.checkCollision.down = false;

// Player is now able to stand on the platform
this.physics.add.collider(this.player, this.platforms);

// Detect two object colliding
this.physics.add.overlap(this.player, this.coin, this.callback);  // callback() {...}
// One-liner
this.physics.add.overlap(this.player, this.coin, (player, coin) => {
    coin.body.enable = false;  // Disable the physics, make it trigger only once
    this.tweens.add({
        targets: coin,
        alpha: 0,
        duration: 500,
        onComplete: () => {
            coin.destroy();
        }
    });
});

// Fix object - Pin it stick to camera
this.scoreText = this.add.text(100, 100, `Score: 10,000`, { 
    fontSize: '26px',
    fontFamily: 'sans-serif',
    color: '#FFFFFF',
});
this.scoreText.setScrollFactor(0);  // Make object sticky to camera

Plugins

BBCode Text Plugin

Document: https://rexrainbow.github.io/phaser3-rex-notes/docs/site/bbcodetext/

preload() {
  this.load.plugin('rexbbcodetextplugin', 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rexbbcodetextplugin.min.js', true);
}

create() {
  this.add.rexBBCodeText(100, 100, "I'm [b][color=#FF0000]changing[/color][/b] the text \n inside the label letiable!", {
    fontSize: '30px',
    fontFamily: 'Arial, Sans-serif',
    backgroundColor: '#F8D38A',
    padding: { left: 50, right: 50, top: 10, bottom: 10 },
    stroke: '#000',
    strokeThickness: 5,
    align: 'center',
    lineSpacing: 10,
    wordWrap: { width: 450, useAdvancedWrap: true },
  });
}

Scrollable Panel Plugin

Document: https://rexrainbow.github.io/phaser3-rex-notes/docs/site/ui-scrollablepanel/

preload() {
    // Load Rex UI Plugin
    this.load.scenePlugin({
        key: 'rexuiplugin',
        url: 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rexuiplugin.min.js',
        sceneKey: 'rexUI'
    });
}

create() {
  const scrollablePanel = this.rexUI.add.scrollablePanel({
    x: 400,
    y: 300,
    width: 200,
    height: 400,
    scrollMode: 'y',  // vertical scrolling
    background: this.rexUI.add.roundRectangle(0, 0, 2, 2, 10, 0x1B5B9B),
    panel: {
      child: this.rexUI.add.sizer({
        orientation: 'y',   // vertical scrolling bar
        space: { item: 10 },
      })
      .add(
        this.add.text(0, 0, 'Very long text 1. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', {
          wordWrap: { width: 150, useAdvancedWrap: true },
        })
      )
      .add(
        this.add.text(0, 0, 'Another elements\n')
      )
    },
    slider: {
      track: this.rexUI.add.roundRectangle({
        width: 20, 
        radius: 10,
        color: '0x666666',
      }),
      thumb: this.rexUI.add.roundRectangle({
        radius: 13,
        color: '0x888888',
      }),
    },
  })
  .layout();
}

Move To Plugin

Reference: https://github.com/rexrainbow/phaser3-rex-notes/blob/master/docs/docs/moveto.md

preload(){
    this.load.plugin('rexmovetoplugin', 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rexmovetoplugin.min.js', true);
}
create(){
    this.player.walk = this.plugins.get('rexmovetoplugin').add(this.player[i], {
        speed: 50,
        rotateToTarget: false
    });
    this.player.walk.moveTo(200, 200);
}

Webfont Loader Plugin

Reference: https://rexrainbow.github.io/phaser3-rex-notes/docs/site/webfontloader/#__code_10

constructor() {
    super({
        key: 'examples',
        pack: {
            files: [{
                type: 'plugin',
                key: 'rexwebfontloaderplugin',
                url: 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rexwebfontloaderplugin.min.js',
                start: true
            }]
            }
    });
}
preload(){
    /* Load plugin */
    this.plugins.get('rexwebfontloaderplugin').addToScene(this);
    this.load.rexWebFont({
        google: {
            families: ['VT323']
        },
        custom: {
            families: ['My Font', 'My Other Font:n3,n5,n7'],
            urls: ['/fonts.css']
        },
    });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment