Cuando trabajamos con Phaser, y una vez conocemos como funcionan las escenas de Phaser, necesitamos crear elementos y añadirlos a nuestro juego. Estos elementos se llaman "objetos" en Phaser y pueden ser imágenes, textos, formas geométricas, etc.
Antes de entrar en detalle sobre tipos de objetos, vamos a entender como se añaden los objetos, ya que todos siguen casi la misma forma de creación, y una vez sabes como hacer para crear uno, es bastante intuitivo crear los demás.
Crear y añadir un objeto
La forma más sencilla de añadir objetos en Phaser es utilizando el método add.image()
. Este método añade un objeto a la escena y lo posiciona en las coordenadas x,y
indicadas. Observa que siempre que utilicemos una imagen en Phaser, antes, en el método preload()
hay que precargarla con load.image()
, indicándole el nombre (key) y la ruta:
const SPRITES_PATH = "assets/sprites";
export class Screen extends Phaser.Scene {
preload() {
this.load.image("logo", `${SPRITES_PATH}/logo.png`);
}
create() {
const logo = this.add.image(0, 0, "logo");
}
}
De forma opcional, podemos guardar ese objeto creado en una variable logo
, o en una variable de clase this.logo
para utilizarla posteriormente y cambiar detalles o interactuar con la imagen. Esta forma es la recomendada para simplificar lo máximo posible la creación de objetos, por lo que debería ser nuestra primera opción.
Añadir un objeto existente
En algunas ocasiones, nos interesará crear primero el objeto manualmente y luego añadirlo a la escena. De esta forma, podremos hacer cambios antes de añadirlo. En este caso, utilizaremos el método add.existing()
:
const SPRITES_PATH = "assets/sprites";
export class Screen extends Phaser.Scene {
preload() {
this.load.image("logo", `${SPRITES_PATH}/logo.png`);
}
create() {
const logo = new Phaser.GameObjects.Image(this, 0, 0, "logo");
this.add.existing(logo);
}
}
En este ejemplo, observa que hemos creado el objeto de forma manual, utilizando Phaser.GameObjects.Image
y pasándole por parámetro la escena donde vamos a crearlo, las coordenadas y el nombre de la imagen. Luego, añadimos el objeto. Esto puede ser especialmente útil cuando ese logo
se crea dinámicamente en otro fichero y queremos pasarle la referencia, o lo cargamos desde un archivo JSON, por ejemplo.
Crear un objeto personalizado
Quizás, la mejor forma, pero la que puede resultar más compleja, es la de crearnos nuestro propio objeto. Esto nos permitiría tener una clase específica con la información y métodos especializados para ese objeto. En este caso, la idea sería crear una clase que herede de Phaser.GameObjects.Image
y añadirle nuestra propia funcionalidad. Este podría ser nuestro fichero src/scenes/images/Logo.js
:
import Phaser from "phaser";
export class Logo extends Phaser.GameObjects.Image {
constructor(scene, x, y, key) {
super(scene, x, y, key);
scene.add.existing(this);
}
reduceSize() {
this.setScale(0.75);
}
}
Observa que en esta clase, al extender de Phaser.GameObjects.Image
, nuestra clase Logo
es a la misma vez una imagen de Phaser. Por parámetro recibe una referencia de la escena donde nos encontramos, por lo que en este caso:
scene
es lo que usabamos en la escena comothis
- Ahora
this
apunta a nuestra imagen, y no a la escena
Por lo tanto, en este caso, lo que debemos escribir para añadir la imagen ya existente (nuestra clase Logo) a la escena, sería scene.add.existing(this)
. Por otro lado, añadimos también un método de apoyo que reescala la imagen.
Ahora, en nuestra escena, haríamos esto:
import { Logo } from "@/scenes/images/Logo.js";
const SPRITES_PATH = "assets/sprites";
export class Screen extends Phaser.Scene {
preload() {
this.load.image("logo", `${SPRITES_PATH}/logo.png`);
}
create() {
const logo = new Logo(this, 400, 300, "logo");
logo.reduceSize();
}
}
Es un poco más complicado que en los casos anteriores, pero nos permite separar la lógica por clases y así tener una mejor organización y hacer mucho más fácil reutilizar los objetos. Si nuestro juego va a ser muy grande, es una práctica altamente recomendable.