> Manuales > Manual de Phaser 3

Cómo es el ciclo de vida de una escena con el motor de juegos Javascript Phaser, con sus principales métodos para realizar sus funciones básicas: inicialización. precarga, creación y update.

Ciclo de vida de una escena de Phaser

En el anterior artículo pudimos entender cómo se realiza un juego HTML5 usando el motor Javascript Phaser. Vimos cómo iniciar un proyecto, como instalar el framework y cómo crear un juego con una escena simple.

Lo cierto es que hasta el momento no hemos hecho gran cosa, por lo que sería mucho decir que hemos construido un juego, sin embargo en este artículo vamos a comenzar a aportar algo de interactividad, por lo que nuestro ejemplo mejorará un poco. Lo haremos a partir de la programación de una escena y la implementación de los métodos del ciclo de vida.

Nota: En todo momento vamos a usar el modelo de creación de escenas basado en una clase ES6, sin embargo, conviene decir que Phaser 3 hereda un método de creación de escena basado en un objeto, que es el que se usaba en Phaser 2, que si lo prefieres podrías usar también.

Constructor

El constructor es un método que resume las tareas de inicialización de los objetos. En Phaser es el lugar adecuado para colocar código de configuración de la escena, que se ejecutará una única vez.

Lo más básico es asignarle un nombre a la escena, como vimos en el artículo anterior.

constructor() {
  super({ key: 'game' });
}

Pero podríamos agregar más configuración a la escena como por ejemplo si está activa desde el principio, si tiene una física particular, las cámaras y mucho más.

Método init()

El método init() sirve para realizar tareas de inicialización que se deben ejecutar cada vez que la escena se pone en marcha.

Una escena puede arrancarse y detenerse cualquier número de veces. En el arranque inicial o en cualquier sucesivo rearranque se ejecutará el código que tengamos en init().

Nota: Una escena puede pausarse y reanudar su ejecución. En esos casos no se ejecutaría el método init(), porque la escena solamente se detuvo unos instantes. Este por ejemplo sería un hipotético control de pausar el juego. Los casos en los que se arrancará de nuevo la escena, ejecutando el método init(), y otros métodos que le siguen, son aquellos en los que la escena se aborte completamente, por ejemplo cuando se inicia de nuevo el juego porque el jugador perdió la partida. Esto lo vermos con detalle más adelante, porque es materia más adecuada de tratar en el momento en el que tengamos varias escenas en el juego.

Método preload()

Después del método init() se ejecutará el código del método preload(). En este método colocamos todas las prepargas de archivos que se requieran para esta escena (o también si lo deseamos para escenas siguientes). Obviamente, si un recurso ya estaba cargado, porque ya se había precargado en una ejecución anterior, no se vuelve a solicitar.

Vamos a modificar un poco este método con respecto al que teníamos en el artículo anterior, para colocarle una nueva imagen que vamos a precargar.

preload() {
    this.load.image('background', 'images/background.png');
    this.load.image('gameover', 'images/gameover.png');
    this.load.image('platform', 'images/platform.png');
}

Hemos introducido una nueva imagen, a la que hemos asignado el identificador "platform". Es una plataforma que nosotros vamos a mover con el teclado, como en el clásico juego de los años 80, "Arkanoid".

Todos los recursos precargados se obtienen del servidor. Hasta el momento que no se han cargado completamente, y no se disponen de todos listos para usarse, la escena no continúa ejecutando los métodos siguientes.

Solo para dejarlo muy claro, que hayas precargado un recurso no significa que se vaya a ver todavía en ningún lugar. El siguiente método nos servirá para eso.

Método create()

El flujo de ejecución de la escena continúa con el método create(). Este sirve para componer todo el escenario y los actores que forman la escena.

En este método iremos colocando imágenes, asignando comportamientos, definiendo colisiones, animaciones y cosas similares.

Este era el código del método hasta este punto.

create() {
    this.add.image(410, 250, 'background');
    this.gameoverImage = this.add.image(400, 90, 'gameover');
}

Ahora le vamos a ir agregando más líneas para ir añadiendo la plataforma. Pero antes vamos a hacer que la imagen de "game over" desaparezca, por motivos obvios. Esto lo conseguimos con la propiedad "visible" del objeto image.

this.gameoverImage.visible = false;

Ahora agregamos la plataforma en la parte inferior de la página. Vamos a comenzar con un código como este para ver lo que pasa.

this.platform = this.physics.add.image(400, 460, 'platform');

Si te fijas, la imagen de la plataforma aparece en la parte de abajo y se cae nada más arrancar, como consecuencia de la gravedad. Nuestra plataforma debería quedarse en el sitio, por lo que la gravedad no le debería afectar. Esto lo conseguimos con la siguiente línea:

this.platform.body.allowGravity = false;

Por último dentro del método create vamos a incorporar una línea extra, que nos permite acceder al estado de las teclas del cursor.

this.cursors = this.input.keyboard.createCursorKeys();

Estas teclas las vamos a usar luego para mover la plataforma. En este caso solamente hemos creado un objeto "cursors" que nos dirá si estas teclas se encuentran pulsadas en un momento dado.

Método update()

Este método es el corazón del juego. Es un método que se ejecuta constantemente y nos permite especificar el código que debe estar pendiente de las acciones del usuario.

Básicamente aquí vamos a preguntarnos si el usuario ha pulsado uno de los botones del cursor, en cuyo caso reaccionaremos de distintas maneras.

update() {
  if (this.cursors.left.isDown) {
    this.platform.setVelocityX(-500);
  }
  else if (this.cursors.right.isDown) {
    this.platform.setVelocityX(500);
  }
  else {
    this.platform.setVelocityX(0);
  }
}

El método update se ejecuta muy de seguido, muchas veces por segundo. Entonces le preguntamos si el usuario tiene pulsado la tecla izquierda del cursor. En ese caso le asignamos una velocidad a la plataforma de valor -500, en el eje de las "x", lo que hace que se mueva en la dirección de la flecha pulsada. En el caso que la tecla de la derecha esté pulsada, entonces la velocidad en el eje de las "x" será de 500.

El valor de la velocidad es como el de la gravedad, a mayor valor más rápido se mueve.

En caso que no se esté pulsando ni izquierda ni derecha, entonces la velocidad en el eje de las "x" se pone a cero.

Con esto ya puedes ejecutar el juego tal como lo tenemos ahora. Verás como las teclas del cursor, izquierda y derecha, hacen que se mueva la plataforma.

El método update() se ejecutará constantemente... muchas veces por segundo, con ello se consigue que los juegos sean muy fluidos, porque están en constante actualización de sus elementos. Como hemos colocado el control de las teclas del cursor en el método update(), el juego responderá constantemente a los cursores y así podremos mover la plataforma con el teclado mientras la escena esté activa.

Ten en cuenta que el foco de la aplicación tiene que estar en el elemento canvas de la página, es decir, en el lienzo del juego. Asi que, si no hacen nada las teclas del cursor, simplemente haz clic encima del juego y prueba a mover de nuevo la plataforma. No obstante, Phaser se suele encargar de poner el foco en el juego al cargar la página, por lo que no debería darte problema este punto.

Existen métodos de control de ese flujo de ejecución, como cuando una escena se pausa o se detiene, en cuyo caso deja de producirse ese bucle de ejecución del update(). Más adelante explicaremos cómo podemos parar las escenas, movernos entre unas escenas y otras y cosas similares.

Con lo que hemos hecho hasta el momento, hemos conseguido una pequeña mejora al juego, todavía básica pero bien representativa, porque ahora es capaz de atender las acciones del usuario.

Todavía no es muy espectacular, pero ya podemos ver algo más y usar el cursor del teclado para mover un elemento por la pantalla. Tal como está el juego verás algo como esto:

Ciclo de vida de una escena de Phaser

Código completo de la escena

Para que quede constancia, aquí encuentras el código completo de la escena que hemos venido desarrollando en esta práctica.

export class Game extends Phaser.Scene {

  constructor() {
    super({ key: 'game' });
  }

  preload() {
    this.load.image('background', 'images/background.png');
    this.load.image('gameover', 'images/gameover.png');
    this.load.image('platform', 'images/platform.png');
  }

  create() {
    this.add.image(410, 250, 'background');
    this.gameoverImage = this.add.image(400, 90, 'gameover');
    this.gameoverImage.visible = false;
    
    this.platform = this.physics.add.image(400, 460, 'platform');
    this.platform.body.allowGravity = false;
    
    this.cursors = this.input.keyboard.createCursorKeys();
  }

  update() {
    if (this.cursors.left.isDown) {
      this.platform.setVelocityX(-500);
    }
    else if (this.cursors.right.isDown) {
      this.platform.setVelocityX(500);
    }
    else {
      this.platform.setVelocityX(0);
    }
  }

}

El código del juego completo y las imágenes que hemos usado hasta ahora, lo puedes ver en este enlace a GitHub.

En el próximo artículo veremos cómo insertar nuevos actores en el juego, como una bola que rebote por la pantalla y en la plataforma, para que nuestra práctica vaya tomando algo más de sentido. De esa manera podremos comenzar a trabajar con el sistema de físicas de Phaser, para detectar colisiones conseguir que rebote la bola.

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online Escu...

Manual