Flappy Bird con Phaser

Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.

Cargar fondo

Héroe con físicas y animación

import hero from './assets/img/heroe.png';

class FlappyBird extends Phaser.Scene {
	preload() {
		...
		this.load.spritesheet('heroe', hero, {frameWidth: 50, frameHeight: 50});
	}

	create() {
		this.player = this.physics.add.sprite(50, 100, 'heroe');

		this.anims.create({
			key: 'fly',
			frames: this.anims.generateFrameNumbers('heroe', {start: 0, end: 1}),
			frameRate: 10,
			repeat: -1,
		});
		this.player.play('fly');
	}
}

...
physics: {
	default: 'arcade',
	arcade: {
		debug: true,
		gravity: {
			y: 300,
		},
	},
},

Saltar con space

create(){
	...
	this.input.keyboard.on('keydown', (event) => {
		if (event.keyCode === 32) {
			this.jump();
		}
	});
}

jump() {
	this.player.setVelocityY(-200);
}

Saltar con click en la pantalla

this.input.on('pointerdown', () => this.jump());

Animación al saltar

this.anims.create({
	key: 'jump',
	frames: this.anims.generateFrameNumbers('heroe', {start: 2, end: 2}),
	frameRate: 7,
	repeat: 1,
});

jump() {
	this.player.setVelocityY(-200);
	this.player.play('jump');
}

Seguir volando

En el métdodo create():this.player.on('animationcomplete', this.animationComplete, this);
animationComplete(animation, frame, sprite) {
	if (animation.key === 'jump') {
		this.player.play('fly');
	}
}

Las tuberías

nuevaColumna() {
	//Una columna es un grupo de cubos
	const columna = this.physics.add.group();
	//Cada columna tendrá un hueco (zona en la que no hay cubos) por dónde pasará el super héroe
	const hueco = Math.floor(Math.random() * 5) + 1;
	for (let i = 0; i < 8; i++) {
    	//El hueco estará compuesto por dos posiciones en las que no hay cubos, por eso ponemos hueco +1
		if (i !== hueco && i !== hueco + 1 && i !== hueco - 1) {
			const cubo = columna.create(960, i * 100, 'pipe');
			cubo.body.allowGravity = false;
		}
	}
	columna.setVelocityX(-200);
	//Detectaremos cuando las columnas salen de la pantalla...
	columna.checkWorldBounds = true;
	//... y con la siguiente línea las eliminaremos
	columna.outOfBoundsKill = true;
	//Cada 1000 milisegundos llamaremos de nuevo a esta función para que genere una nueva columna
	this.time.delayedCall(1000, this.nuevaColumna, [], this);
}

Colisión con tuberías

Última línea del método nueva columna:this.physics.add.overlap(this.player, columna, this.hitColumna, null, this);
hitColumna() {
	alert('game over');
}

Poner tapas a las tuberías

if (i == hueco - 2) {
	cubo = columna.create(960, i * 100, 'pipeArriba');
} else if (i == hueco + 2) {
	cubo = columna.create(960, i * 100, 'pipeAbajo');
} else {
	cubo = columna.create(960, i * 100, 'pipe');
}

Imagen de tuberías aleatoria

const aleatorio = Math.floor(Math.random() * 2);
for (let i = 0; i < 8; i++) {
	//El agujero son cuatro casillas
	if (i !== hueco && i !== hueco + 1 && i !== hueco - 1) {
		let cubo;
		if (i == hueco - 2) {
			cubo = columna.create(960, i * 100, `pipeArriba${aleatorio}`);
		} else if (i == hueco + 2) {
			cubo = columna.create(960, i * 100, `pipeAbajo${aleatorio}`);
		} else {
			cubo = columna.create(960, i * 100, `pipe${aleatorio}`);
		}
		cubo.body.allowGravity = false;
	}
}

Escena fin de juego

Definimos la escena que se cargará cuando el jugador pierda.

Volver a jugar

Cuando llegamos a la escena de perder, si el jugador pulsa sobre la pantalla, volveremos a la escena inicial de juego.

this.input.on('pointerdown', () => this.volverAJugar())

Fondo animado

create() {
	this.bg = this.add.tileSprite(480, 320, 960, 640, 'fondo').setScrollFactor(0);
	...
}

update(time){
	this.bg.tilePositionX = time*0.1;
}

Detectar cuando el player sale de la pantalla

create(){
	...
	this.physics.world.on('worldbounds', (body) => {
		this.scene.start('Lose');
	});

	this.player.setCollideWorldBounds(true);
	this.player.body.onWorldBounds = true;
}

← Galería de tiro con PhaserJS
Pong con Phaser →