Phaser está basado en el paradigma de la orientación a objetos, por lo que al crear una imagen, tenemos a nuestra disposición múltiples propiedades y métodos para manipular y modificar nuestra imagen. Echemos un vistazo a las cosas que podemos realizar con una imagen.
Cargar una imagen en Phaser
Lo primero y esencial, recordemos que es cargar la textura de una imagen y darle un nombre (en la fase de preload) y luego añadirla a nuestro juego. Esto se puede hacer con el siguiente código en nuestra escena:
import Phaser from "phaser";
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");
}
}
Recuerda que es imprescindible realizar el proceso de carga de texturas antes de añadirla, de lo contrario nos aparecerá un cuadrado verde, con una línea diagonal, que simboliza que no ha encontrado la textura o imagen indicada.
Tienes más información sobre las diferentes formas de crear objetos en Phaser en este artículo.
Posición de la imagen
Si nos fijamos, al utilizar el método this.add.image()
hemos indicado la posición de la pantalla donde vamos a colocar nuestra imagen. En este ejemplo hemos indicado 0x0
, lo que significa que se ubicará en el punto superior izquierdo de la pantalla.
En cualquier momento podemos modificar esta posición, simplemente indicando los nuevos valores con el método .setPosition()
:
create() {
const logo = this.add.image(0, 0, "logo");
logo.setPosition(100, 25);
// O por separado (interesante si sólo queremos cambiar una):
logo.setX(100);
logo.setY(25);
// Si queremos consultar la posición:
console.log(logo.x); // 100
console.log(logo.y); // 25
}
Un detalle importante a tener en cuenta es que las imágenes tienen por defecto establecido el punto de origen en el centro de la imagen. En Phaser, el punto de origen es un valor de 0
a 1
, donde 0
es el inicio y 1
es el final. Por ejemplo, 0x0
sería la esquina superior-izquierda, 1x1
sería la esquina inferior-derecha y 1x0.5
sería todo a la derecha y al centro en el eje Y
.
Para poder colocar más fácil nuestra imagen, podemos cambiar el punto de origen de esta forma:
create() {
const logo = this.add.image(0, 0, "logo")
.setOrigin(0, 0)
.setPosition(0, 0);
}
Hemos establecido el punto de origen en el punto 0x0
(la esquina superior-izquierda) y la hemos colocado en la posición 0,0
de la escena. Además, en este caso, en lugar de repetir varias veces la variable logo
para llamar a los métodos, he encadenado un método con otro, para simplificar el código.
Por aquí tienes otras propiedades y métodos interesantes para imágenes en Phaser. Ten en cuenta que la propiedad depth
, en el caso de tener muchas imágenes, nos permite moverlas delante o detrás de las demás imágenes, similar a como lo hace z-index
en CSS:
Propiedad | Método asociado | Descripción |
---|---|---|
x y | setX() setY() setPosition() | Posición de la imagen en x,y . |
originX originY | setOrigin() | Punto de origen de la imagen. |
displayOriginX displayOriginY | setDisplayOrigin() | Punto de origen visual (aparente). |
scrollFactorX scrollFactorY | setScrollFactorX() setScrollFactorY() | Factor de desplazamiento horizontal y vertical. |
depth | setDepth() | Profundidad de elemento respecto a otros. |
Rotación y tamaños
Obviamente, podemos modificar la rotación o los tamaños de una imagen. Para ello utilizaremos algunos de los siguientes métodos:
Propiedad | Método asociado | Descripción |
---|---|---|
angle / rotation | setRotation() | Ángulo de rotación (grados), rotation (radianes). |
displayWidth displayHeight | setDisplaySize() | Anchura o altura visual en píxels. |
scale scaleX scaleY | setScale() setScaleX() setScaleY() | Escala la proporción de la imagen (de 0 a 1 ). |
width / height | setSize() | Anchura o altura (usado para colisiones o interacciones). |
flipX flipY | setFlipX() / toggleFlipX() setFlipY() / toggleFlipY() | Invierte la imagen horizontal o verticalmente. |
Veamos algunos ejemplos con estos métodos:
create() {
const logo = this.add.image(0, 0, "logo");
logo.setRotation(45); // Rotamos 45 grados
logo.setScale(0.5); // Imagen de 100x100 se reduce a 50x50 (0.5 = 50%)
logo.setDisplaySize(100, 50); // Imagen de 100x100 se reduce a 100x50 (se deforma)
logo.flipX(true); // Imagen se invierte horizontalmente
logo.toggleFlipY(true); // Imagen se invierte verticalmente
}
Observa que también hay un método setSize()
. Este método, a diferencia de setDisplaySize()
se utiliza para cambiar el tamaño de la imagen respecto a tareas de interacción (colisiones, pulsar sobre ella, etc...), pero no respecto a como se ve visualmente.
Recortar imagen
Nos puede interesar en algún momento realizar un recorte (conocido como crop) para quedarnos con sólo un fragmento de la imagen. Esto es muy sencillo de realizar con el método setCrop(x, y, w, h)
. Simplemente, indicamos el punto x,y
donde vamos a empezar a recortar, y el tamaño de ancho y de alto donde vamos a hacer recorte:
Propiedad | Método asociado | Descripción |
---|---|---|
isCropped | setCrop() | Comprueba si la imagen está recortada. |
Por ejemplo, en el siguiente código añadimos una imagen que ocupa 880x199
píxels. Con setCrop()
recortamos el fragmento desde 0,0
que ocupa 145x199
píxels:
create() {
const logo = this.add.image(0, 0, "logo");
logo.setCrop(0, 0, 145, 199);
console.log(logo.isCropped); // true
}
Finalmente, con la propiedad isCropped
podemos saber si la imagen está recortada o no.
Tintar una imagen
Una operación rápida que podría interesarnos es la de tintar una imagen. Phaser tiene algunos métodos para realizar estas operaciones, vamos a analizarlas:
Propiedad | Método asociado | Descripción |
---|---|---|
tintFill | setTintFill() clearTintFill() | Relleno de tinta de la imagen. |
tint | setTint() clearTint() | Tinta de la imagen. |
isTinted | Comprueba si la imagen tiene tinta. |
En primer lugar, vamos a utilizar setTintFill()
, que permite aplicar un color sólido, reemplazando la imagen, pero conservando su forma. Ten en cuenta que se le puede pasar uno o varios parámetros:
create() {
const logo = this.add.image(0, 0, "logo");
// Aplica el color rojo #ff0000 a toda la imagen
logo.setTintFill(0xff0000);
// Aplica colores diferentes a cada esquina de la imagen
logo.setTintFill(0xff0000, 0x00ff00, 0x0000ff, 0xff00ff);
}
Los colores se aplican en formato hexadecimal (numérico), simplemente cambiando el #
por un 0x
. Por otro lado, también tenemos el metodo setTint()
, que a diferencia de setTintFill()
aplica la tinta como si fuera un modo de fusión, por lo que conserva parte de los colores y textura original.
Además de todo esto, tenemos también los métodos clearTint()
y clearTintFill()
para borrar el tintado de una imagen o el isTinted
para comprobar si una imagen está tintada o no.
Visibilidad de una imagen
De forma similar, también se puede modificar la visibilidad de una imagen, utilizando sus canales alfa y modificando el grado de transparencia, o utilizando sus modos de fusión:
Propiedad | Método asociado | Descripción |
---|---|---|
alpha | setAlpha() | Transparencia del objeto. |
blendMode | setBlendMode() | Modo de fusión en la imagen. |
visible | setVisible() | Muestra u oculta la imagen. |
active | setActive() | Activa o desactiva el objeto. |
create() {
const logo = this.add.image(0, 0, "logo");
// Pone la opacidad del logo al 25%
logo.setAlpha(0.25);
// Aplica opacidades diferentes a cada esquina de la imagen
logo.setAlpha(1, 0.5, 0.1, 0.05);
}
Por otro lado, Phaser tiene también un sistema de modos de fusiones para combinar imágenes con otras imágenes o colores. Es algo similar a lo que vimos con setTint()
, pero también se puede aplicar a múltiples imágenes:
const image = this.add.image(0, 0, "image");
const logo = this.add.image(0, 0, "logo");
logo.setBlendMode(Phaser.BlendModes.MULTIPLY);
logo.setVisible(false);
logo.setActive(true);
Existen varios modos de fusión que podemos utilizar, donde los más comunes podrían ser ADD
, MULTIPLY
, NORMAL
y SCREEN
.
Por otro lado, tenemos dos estados muy importantes en los objetos: setVisible()
y setActive()
. Igual que las escenas, un objeto de Phaser también puede estar activo y visible (o no). Por un lado, que un objeto sea visible simplemente indica si la imagen debe renderizarse visualmente, pero si está activo puede seguir actualizándose su lógica. Por otro lado, que un objeto se encuentre activo significa que su lógica seguirá actualizándose, pero puede no ser visible si visible está a false
:
Visible | Activo | Descripción |
---|---|---|
✅ | ✅ | El objeto es visible y sigue actualizando su lógica. |
❌ | ✅ | El objeto es invisible, pero sigue actualizándose su lógica. |
✅ | ❌ | El objeto es visible, pero no actualiza su lógica. |
❌ | ❌ | El objeto no se renderizará visualmente ni actualizará su lógica. |