While Phaser 3 is becoming more and more stable, there’s still a lot to do and learn with Phaser 2, especially if you have games developed with Phaser 2 and want to keep them up to date or port to Phaser 3.
I made a Flappy Bird prototype about three years ago and it’s time to update it to the latest Phaser 2 version before showing you how to port to Phaser 3 line by line.
Also, I added some more room for customization and I not destroy any sprite during the game, I only recycle them saving memory and improving performance.
Have a look at the prototype:
Use the mouse to flap.
Now, let me show you the source code, still uncommented but rather easy to read, with a lot of customizable options:
var game; var gameOptions = { // bird gravity, will make bird fall if you don't flap birdGravity: 800, // horizontal bird speed birdSpeed: 125, // flap thrust birdFlapPower: 300, // minimum pipe height, in pixels. Affects hole position minPipeHeight: 50, // distance range from next pipe, in pixels pipeDistance: [220, 280], // hole range between pipes, in pixels pipeHole: [100, 130], // local storage object name localStorageName: "bestFlappyScore" } window.onload = function() { game = new Phaser.Game(320, 480, Phaser.CANVAS); game.state.add("Play", play, true); } var play = function(){} play.prototype = { preload:function(){ game.load.image("bird", "bird.png"); game.load.image("pipe", "pipe.png"); }, create:function(){ game.stage.backgroundColor = "#87CEEB"; game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; game.scale.pageAlignHorizontally = true; game.scale.pageAlignVertically = true; game.stage.disableVisibilityChange = true; game.physics.startSystem(Phaser.Physics.ARCADE); this.pipeGroup = game.add.group(); this.score = 0; this.topScore = localStorage.getItem(gameOptions.localStorageName) == null ? 0 : localStorage.getItem(gameOptions.localStorageName); this.scoreText = game.add.text(10, 10, "-", { font:"bold 16px Arial" }); this.updateScore(0); this.bird = game.add.sprite(80, 240, "bird"); this.bird.anchor.set(0.5); game.physics.arcade.enable(this.bird); this.bird.body.gravity.y = gameOptions.birdGravity; game.input.onDown.add(this.flap, this); var pipePosition = game.width do{ this.addPipe(pipePosition); pipePosition += game.rnd.between(gameOptions.pipeDistance[0], gameOptions.pipeDistance[1]); } while(pipePosition < game.width * 4); }, update:function(){ game.physics.arcade.collide(this.bird, this.pipeGroup, this.die, null, this); if(this.bird.y > game.height || this.bird.y < 0){ this.die(); } }, updateScore: function(inc){ this.score += inc; this.scoreText.text = "Score: " + this.score + "\nBest: " + this.topScore; }, flap: function(){ this.bird.body.velocity.y = -gameOptions.birdFlapPower; }, die: function(){ localStorage.setItem(gameOptions.localStorageName, Math.max(this.score, this.topScore)); game.state.start("Play"); }, addPipe: function(posX){ var pipeHoleHeight = game.rnd.between(gameOptions.pipeHole[0], gameOptions.pipeHole[1]); var pipeHolePosition = game.rnd.between(gameOptions.minPipeHeight + pipeHoleHeight / 2, game.height - gameOptions.minPipeHeight - pipeHoleHeight / 2); var upperPipe = new Pipe(game, posX, pipeHolePosition - pipeHoleHeight / 2, -gameOptions.birdSpeed); game.add.existing(upperPipe); upperPipe.anchor.set(0.5, 1); this.pipeGroup.add(upperPipe); var lowerPipe = new Pipe(game, posX, pipeHolePosition + pipeHoleHeight / 2, -gameOptions.birdSpeed); game.add.existing(lowerPipe); lowerPipe.anchor.set(0.5, 0); this.pipeGroup.add(lowerPipe); } } Pipe = function (game, x, y, speed) { Phaser.Sprite.call(this, game, x, y, "pipe"); game.physics.enable(this, Phaser.Physics.ARCADE); this.body.velocity.x = speed; this.giveScore = true; }; Pipe.prototype = Object.create(Phaser.Sprite.prototype); Pipe.prototype.constructor = Pipe; Pipe.prototype.update = function() { if(this.x + this.width < game.state.states[game.state.current].bird.x && this.giveScore){ game.state.states[game.state.current].updateScore(0.5); this.giveScore = false; } if(this.x < -this.width){ this.giveScore = true; game.state.states[game.state.current].pipeGroup.sort("x", Phaser.Group.SORT_DESCENDING); if(game.state.states[game.state.current].pipeGroup.getChildAt(0).x == game.state.states[game.state.current].pipeGroup.getChildAt(1).x){ this.x = game.state.states[game.state.current].pipeGroup.getChildAt(0).x + game.rnd.between(gameOptions.pipeDistance[0], gameOptions.pipeDistance[1]); } else{ this.x = game.state.states[game.state.current].pipeGroup.getChildAt(0).x; } } };
The game is managed by ARCADE physics, and during next days you will see it improved and ported to Phaser3, meanwhile download the source code.