Fall down

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

En este juego tendremos misiles que irán callendo de la parte superior de la pantalla. El objetivo es pulsar sobre los misiles antes de que colisionen sobre la faz de la tierra. Tendremos la posibilidad de que tres misiles colisionen contra la tierra antes de perder la partida.

Pasos en la resolución del juego falldown con phaserJS

Cargar fondo

Tal como hemos hecho en juegos anteriores, cargamos la imagen de fondo de la escena principal. Para ello, precargaremos la imagen en la escena Boot.js y la cargaremos en Game.js.

Físicas

La función launchMissile se encargará de lanzar un misil desde la parte superior de la pantalla. Como estamos utilizando físicas, el misil caerá por gravedad, aunque la daremos un pequeño empujoncito inicial utilizando la función setVelocity.

Recuerda que:

  • Para utilizar físicas, debes definirlo en el fichero main.js.
  • Para cargar missile0 en pantalla, deberás precargarlo en el preload de la escena Boot.js.
create() {
 ...
 this.launchMissile();
}

launchMissile() {
 const missile = this.physics.add.sprite(50, 100, 'missile0');
 missile.setVelocity(0, 100);
}
main.js
const config = {
 type: Phaser.AUTO,
 width: 960,
 height: 640,
 scene: Escena,
 scale: {
  mode: Phaser.Scale.FIT
 },
 physics: {
  default: 'arcade',
  arcade: {
   debug: true,
   gravity: {
    y: 300,
   },
  },
 },
};

Poner nuevos misiles cada cierto tiempo

Queremos lanzar varios misiles, no solo uno. Por tanto, la llamada al método launchMissile la repetiremos cada 1000 milisegundos. Esto lo conseguiremos colocando el siguiente código al final de la función launchMissile.

launchMissile() {
 ...
 this.time.delayedCall(1000, this.launchMissile, [], this);
}

Detectar pulsación

Queremos que cuando pulsemos sobre un misil este se destruya. Para ello, al crear el misil lo haremos intereactivo y le añadiremos el listener del evento pointerdown.

missile.setInteractive();
missile.on('pointerdown', () => this.clickedMissile(missile));
clickedMissile(m) {
 m.destroy();
}

Misiles variados

Queremos crear misiles de distintos tipos. Para ello, concatenaremos la palabra missile con un número aleatorio que determinará que misil vamos a cargar.

const random = Math.floor(Math.random() * 2);
const missile = this.physics.add.sprite(50, -100, `missile${random}`);

Diferentes posiciones

Hasta ahora los misiles se creaban siempre en la misma posición. Vamos a crear el misil en una coordenada x que será aleatoria y estará, más o menos entre 0 y el ancho de la pantalla. Hemos sumado 50 y restado 100 para tratar de que el misil siempre caiga completamente dentro de la pantalla, y dando un margen de seguridad teniendo en cuenta sus dimensiones.

launchMissile() {
 ...
 const missilePosition = Math.floor(Math.random() * (gameWidth -100)) + 50;
 ...
}

Cohetes explotan

Al pulsar sobre un misil, este debe explotar. Para ello, como ya hicimos en el juego de la galería de tiro, precargamos el spritesheet de la animación de explosión en el preload de Boot.js y la configuración de la animación en el create.

/src/scenes/Boot.js

preload() {
 ...
 this.load.spritesheet('crash', crash, {
  frameWidth: 199,
  frameHeight: 200
 });
}

create() {
 ...
 this.anims.create({
  key: 'crashAnim',
  frames: this.anims.generateFrameNumbers('crash', {start: 0, end: 4}),
  frameRate: 7
 });
}

Luego, cuando el misil sea pulsado, en lugar de destruirlo, lo que vamos a hacer es detonar la animación de explosión.

/src/scenes/Game.js

clickedMissile(m) {
 m.play("crashAnim");
}

Cohetes explotan y desaparecen

Añadimos un listener que escucha cuando termina cualquier tipo de animación en el objeto missile. Si la animación que termina es la de explosión (crashAnim, que es la única animación que tiene el misil), eliminamos el sprite.

launchMissile(){
 ...
 missile.on('animationcomplete', this.animationComplete, this);
 ...
}

animationComplete(animation, frame, sprite) {
 if (animation.key === 'crashAnim') {
  sprite.destroy();
 }
}

Poner vidas en pantalla

Cada vez que un misil colisione contra la parte inferior de la pantalla, perderemos una vida. Esto lo representaremos mediante unas imágenes con forma de corazón que estarán en la esquina superior izquierda. Cuando el jugador pierda una vida, estas imágenes pasarán de un corazón rojo a uno gris.

De momento, en este paso, colocaremos las vidas en la parte superior de la pantalla.

/src/scenes/Boot.js

preload(){
 ...
 this.load.spritesheet('life', life, {
  frameWidth: 50,
  frameHeight: 50
 });
}

/src/Game.js

create(){
 ...
 this.life1 = this.add.sprite(50, 30, 'life');
 this.life2 = this.add.sprite(100, 30, 'life');
 this.life3 = this.add.sprite(150, 30, 'life');
}

Gestionar vidas

El siguiente código va haciendo que cada vez que el usuario pierda una vida, la imagen que la representa cambie de un corazón rojo a uno gris. Para ello, tendremos un contador de vidas (liveCounter) que iremos decrementando cada vez que un objeto colisione con la parte inferior de la pantalla (esto lo evaluamos con el código if(down)).

Tras decrementar el contador evaluaremos su valor para, en función de él, activar el segundo frame del spritesheet del corazón, que hará que pase de ser un corazón rojo a uno gris.

Finalmente, el último else if hace que si hemos perdido todas las vidas (liveCounter == 0) vayamos a la escena de partida perdida.

Para que todo esto funcione, debemos completar el método de launchMissile indicando que cada uno de los misiles que vamos a ir creando tenga la capacidad de colisionar contra los límites de la pantalla.

create(){
 ...
 this.lifeCounter= 3;

 this.physics.world.on('worldbounds', (body, up, down, left, right) => {
            if (down) {
                body.gameObject.disableBody();
                body.gameObject.play("crashAnim");
                --this.lifeCounter;
                if (this.lifeCounter == 2) {
                    this.life3.setFrame(1);
                } else if (this.lifeCounter == 1) {
                    this.life2.setFrame(1);
                } else if (this.lifeCounter == 0) {
                    this.life1.setFrame(1);
                    this.scene.start('GameOver');
                }
            }
        });
}

launchMissile(){
 ...
 missile.setCollideWorldBounds(true); 
 missile.body.onWorldBounds = true;
}

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