Creating A Flappy Bird Clone In Phaser 3 Beta

 

Creating A Simple Flappy Bird Clone In Phaser 3 Beta!

  • In this tutorial we will be going over how to create a very simple Flappy Bird clone in Phaser 3 Beta using Impact JS for physics.

What we will cover:

  • Creating a simple Flappy Bird clone using Phaser 3

To note this tutorial is being written based on a boilerplate project which can be found here https://github.com/photonstorm/phaser3-project-template

To keep things simple for these new tutorials in Phaser 3 Beta we will be keeping most everything in a single Scene file.

If you are unsure on how to setup a project in Phaser 3 Beta please take a look at this previous tutorial to get a good idea on how to set everything up https://sprite-storm.com/tutorial/creating-physics-sprite-phaser-3-beta/

Defining Our GameScene Class:


class GameScene extends Phaser.Scene {
    constructor() {
        super({
            key: 'GameScene',
            physics: {
                system: 'impact',
                gravity: 250,
                debug: false,
                setBounds: false
            }
        });
    }
}

export default GameScene;

Lets Break This Down:

  • Here we define a pretty standard ES6 class called GameScene that extends a Phaser Scene.
  • We build our constructor and super, our super contains an object with a key of GameScene.

  • Next we define our physics object for our game, we set the system to be used to impact JS, set our world gravity to 250, our debug to false, as well as out bounds to false.

  • Lastly we just export our GameScene

Setting Up Our Preload:


class GameScene extends Phaser.Scene {
    constructor() {
        super({
            key: 'GameScene',
            physics: {
                system: 'impact',
                gravity: 250,
                debug: false,
                setBounds: false
            }
        });
    }

    preload() {
        this.load.image('mushroom', './assets/images/mushroom2.png');
        this.load.image('pipes', './assets/images/pipe.png');
    }
}

export default GameScene;

Lets Break This Down:

  • First off we add our preload function inside of our GameScene class after our constructor.

  • Inside the preload function we call this.load.image() for our two images we will be using in this tutorial function which is built into Phaser 3 Beta.

  • These two preload functions accept two parameters each, first being the key we want to call this image, and second the path to the image in our directory.

Setting Up Our Create Function:


class GameScene extends Phaser.Scene {
    constructor() {
        super({
            key: 'GameScene',
            physics: {
                system: 'impact',
                gravity: 250,
                debug: false,
                setBounds: false
            }
        });
    }

    preload() {
        this.load.image('mushroom', './assets/images/mushroom2.png');
        this.load.image('pipes', './assets/images/pipe.png');
    }

    create() {
        this.mushroom = this.physics.add.image(400, 300, 'mushroom').setActive().setVelocity(0, 0);

        this.input.events.on('POINTER_DOWN_EVENT', () => {
            this.mushroom.setVelocity(0, -150);
        });

        this.pipes = this.add.group();

        this.timedEvent = this.time.addEvent({
            delay: 4500,
            callback: this.addPipeRows,
            callbackScope: this,
            loop: true
        })

        this.mushroom.setTypeA().setCheckAgainstB();

        this.physics.world.events.on('COLLIDE_EVENT', (event) => {
            this.collide(event);
        });
    }
}

export default GameScene;

Lets Break This Down:

  • Firt we begin by defining a variable called this.mushroom which will act as our ‘Bird’ in this clone. We set this variable to Phaser 3 built in functionality of making a image with physics enabled by calling this.physics.add.image() we pass it three parameters which are x, y, and the key to create from.

  • We also call .setActive().setVelocity() to make the physics image active and set its initial velocity. The initial velocity for us is going to be 0, 0.

  • Next we call an event on pointer down this method will accept two paramets, a key which for us is ‘POINTER_DOWN_EVENT’ then it accepts an anonymous function for when this event is triggered.

  • Inside our anonymouse function we will declare that on pointer down we want to alter our mushrooms setVelocity to -150 Y.

  • Next we simply define a variable that will be housing our obstacles, called this.pipes which is adding a group to our game by calling this.add.group().

  • We create a timer event set to a defined variable called timedEvent, in the timer event we pass an object to house some parameters. The delay we want for the event to be triggered, a callback function for when the event is triggered in our case it will call this.addPipeRows which we will get to in a bit, give it our callback scope which will be this. Lastly we pass loop and set it to true.

  • Next we will define some physics things for impact JS, we will call this.mushroom.setTypeA().setCheckAgainstB(); which from my understanding will set our mushroom to type A and set it to check for collision against type B. This is my first time working with Impact JS however and I may not be 100% correct on that.

  • Last but not least for the create function we define a collide event. This event method will accept two parameters, first it will accept the event key which is ‘COLLIDE_EVENT’ next it will accept an anonymous function which accepts one parameter which is event. Inside the anonymous function we will call our custom function for what we want to happen when the collision is detected in our case it is this.collide which also accepts event as a parameter.

Setting Up Our Update Function:


class GameScene extends Phaser.Scene {
    constructor() {
        super({
            key: 'GameScene',
            physics: {
                system: 'impact',
                gravity: 250,
                debug: false,
                setBounds: false
            }
        });
    }

    preload() {
        this.load.image('mushroom', './assets/images/mushroom2.png');
        this.load.image('pipes', './assets/images/pipe.png');
    }

    create() {
        this.mushroom = this.physics.add.image(400, 300, 'mushroom').setActive().setVelocity(0, 0);

        this.input.events.on('POINTER_DOWN_EVENT', () => {
            this.mushroom.setVelocity(0, -150);
        });

        this.pipes = this.add.group();

        this.timedEvent = this.time.addEvent({
            delay: 4500,
            callback: this.addPipeRows,
            callbackScope: this,
            loop: true
        })

        this.mushroom.setTypeA().setCheckAgainstB();

        this.physics.world.events.on('COLLIDE_EVENT', (event) => {
            this.collide(event);
        });
    }

    update() {
        if(this.mushroom.y > this.cameras.main.height) {
            this.gameOver();
        }
    }
}

export default GameScene;

Lets Break This Down:

  • Our update function for this tutorial is quite simple, we have a simple if check to see if our mushroom’s Y is greating than our cameras height for our game we will trigger an event called this.gameOver()

Defining Our Collision Function:


class GameScene extends Phaser.Scene {
    constructor() {
        super({
            key: 'GameScene',
            physics: {
                system: 'impact',
                gravity: 250,
                debug: false,
                setBounds: false
            }
        });
    }

    preload() {
        this.load.image('mushroom', './assets/images/mushroom2.png');
        this.load.image('pipes', './assets/images/pipe.png');
    }

    create() {
        this.mushroom = this.physics.add.image(400, 300, 'mushroom').setActive().setVelocity(0, 0);

        this.input.events.on('POINTER_DOWN_EVENT', () => {
            this.mushroom.setVelocity(0, -150);
        });

        this.pipes = this.add.group();

        this.timedEvent = this.time.addEvent({
            delay: 4500,
            callback: this.addPipeRows,
            callbackScope: this,
            loop: true
        })

        this.mushroom.setTypeA().setCheckAgainstB();

        this.physics.world.events.on('COLLIDE_EVENT', (event) => {
            this.collide(event);
        });
    }

    update() {
        if(this.mushroom.y > this.cameras.main.height) {
            this.gameOver();
        }
    }

    collide(event) {
        event.bodyB.destroy();

        event.gameObjectB.destroy();
        
        this.gameOver();
    }
}

export default GameScene;

Lets Break This Down:

  • When our collide function is triggered from our collision event we will be doing three things.

  • First we destroy the bodyB of the event which will be our mushroom

  • Second we will destroy the actual gameObjectB which is our mushrooms image

  • Lastly we will call our game over function.

  • To note, once again I am not an expert on Impact JS and there may be a better solution for destroying the body and texture however this is what I found to work.

Creating Our Function To Add Pipes:


class GameScene extends Phaser.Scene {
    constructor() {
        super({
            key: 'GameScene',
            physics: {
                system: 'impact',
                gravity: 250,
                debug: false,
                setBounds: false
            }
        });
    }

    preload() {
        this.load.image('mushroom', './assets/images/mushroom2.png');
        this.load.image('pipes', './assets/images/pipe.png');
    }

    create() {
        this.mushroom = this.physics.add.image(400, 300, 'mushroom').setActive().setVelocity(0, 0);

        this.input.events.on('POINTER_DOWN_EVENT', () => {
            this.mushroom.setVelocity(0, -150);
        });

        this.pipes = this.add.group();

        this.timedEvent = this.time.addEvent({
            delay: 4500,
            callback: this.addPipeRows,
            callbackScope: this,
            loop: true
        })

        this.mushroom.setTypeA().setCheckAgainstB();

        this.physics.world.events.on('COLLIDE_EVENT', (event) => {
            this.collide(event);
        });
    }

    update() {
        if(this.mushroom.y > this.cameras.main.height) {
            this.gameOver();
        }
    }

    collide(event) {
        event.bodyB.destroy();

        event.gameObjectB.destroy();
        
        this.gameOver();
    }

    addPipes(x, y) {
        this.pipe = this.physics.add.image(x, y, 'pipes').setActive().setVelocity(-500, 0).setGravity(0).setFixed();

        this.pipes.add(this.pipe);
    }
}

export default GameScene;

Lets Break This Down:

  • We define a function called addPipes which accepts two parameters an X and a Y

  • We create a variable to hold our pipe called this.pipe and create a physics image which accepts an X, Y, key to use in our case will be pipes which we preloaded.

  • We also set this image to be active, we set its velocity to -500, 0 which will cause it to move to the left on our screen. We also set the gravity for our pipe to be 0 therefore it will not be affected by the world gravity.

  • Lastly we add pipe to the pipes group.

Creating Our Function To Create Pipe Rows:


class GameScene extends Phaser.Scene {
    constructor() {
        super({
            key: 'GameScene',
            physics: {
                system: 'impact',
                gravity: 250,
                debug: false,
                setBounds: false
            }
        });
    }

    preload() {
        this.load.image('mushroom', './assets/images/mushroom2.png');
        this.load.image('pipes', './assets/images/pipe.png');
    }

    create() {
        this.mushroom = this.physics.add.image(400, 300, 'mushroom').setActive().setVelocity(0, 0);

        this.input.events.on('POINTER_DOWN_EVENT', () => {
            this.mushroom.setVelocity(0, -150);
        });

        this.pipes = this.add.group();

        this.timedEvent = this.time.addEvent({
            delay: 4500,
            callback: this.addPipeRows,
            callbackScope: this,
            loop: true
        })

        this.mushroom.setTypeA().setCheckAgainstB();

        this.physics.world.events.on('COLLIDE_EVENT', (event) => {
            this.collide(event);
        });
    }

    update() {
        if(this.mushroom.y > this.cameras.main.height) {
            this.gameOver();
        }
    }

    collide(event) {
        event.bodyB.destroy();

        event.gameObjectB.destroy();
        
        this.gameOver();
    }

    addPipes(x, y) {
        this.pipe = this.physics.add.image(x, y, 'pipes').setActive().setVelocity(-500, 0).setGravity(0).setFixed();

        this.pipes.add(this.pipe);
    }

     addPipeRows() {
        let hole = Math.floor(Math.random() * 5) + 1;

        for (let i = 0; i < 12; i++) {
            if (i != hole && i != hole + 1) {
                this.addPipes(800, i * 60 + 10);
            }
        }
    }
}

export default GameScene;

Lets Break This Down:

  • Create a function to create our pipes in rows

  • We define a variable to leave a gap in the rowusing Math.random

  • Next we define a for loop that increments to 12

  • We create an if statement to account for the hole during the for loop

  • Next we create a pipe where ever there is not supposed to be a hole, we call our addPipes function, we pass it an initial X to start at which is 800 and will be off screen, for Y we pass i * 60 + 10 to give some space for the pipes.

  • If all was done correctly so far you should see something like this in your game

Defining GameOver Function:


gameOver() {
    this.scene.start('GameOver');
}

Lets Break This Down:

  • Creating our game over function is quite simple, inside all we do is call this.scene.start(‘GameOver); which will start our game over scene when triggered. I am not going to go over setting up this scene in the index file however if you have followed other tutorials on our site or worked with Phaser 3 Beta it should be simple to add.

Our Game Over Scene:


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

    create() {
      
        this.text = this.make.text(32, 32);
        this.text.x = 350;
        this.text.y = 350;
        this.text.setText('Game Over!')
    }
}

export default GameOver;

Lets Break This Down:

  • Here we define a pretty standard ES6 class called GameOver that extends a Phaser Scene.

  • We build our constructor and super, our super contains an object with a key of GameOver.

  • Next we define our create function which simply creates and adds some text to our scene.

  • Lastly we just export our GameOver scene.

  • If all was done correctly following this entire tutorial this is what you should see when a collision occur and you start your game over scene.

Conclusion:

  • We learned how to create a very basic Flappy Bird clone in Phaser 3 Beta using Impact JS as the physics engine.

Thank you very much for reading. Please stay tuned for upcoming tutorials.

Twitter

Error code 89: Invalid or expired token.

Stay Updated