En el artículo anterior vimos como controlar nuestro juego a través de la personalización de acciones mediante de teclado. En este artículo vamos a hacer lo mismo, pero a través de ratón. En algunos escenarios el ratón puede ser clave para el desarrollo de nuestro videojuego, por lo que estaría bien conocer como gestionarlo en Phaser.
Muchas de las interacciones de ratón en Phaser se realizan mediante eventos. La primera columna son eventos que escuchamos sobre un objeto concreto, mientras que los eventos de la segunda columna son más genéricos:
Evento de objeto | Evento genérico | Descripción |
---|---|---|
pointerdown | gameobjectdown | Se dispara cuando el usuario hace clic en un objeto. |
pointerup | gameobjectup | Se dispara cuando el usuario deja de hacer clic en un objeto. |
pointermove | gameobjectmove | Se dispara continuamente cada vez que el usuario mueve el puntero. |
pointerover | gameobjectover | Se dispara cuando el usuario se mueve sobre un objeto (una vez). |
pointerout | gameobjectout | Se dispara cuando el usuario está dentro del objeto y sale de él. |
wheel | gameobjectwheel | Se dispara cuando el usuario hace scroll sobre un objeto. |
Veamos donde puede ser útil utilizar estos eventos.
El método .setInteractive()
Interactuar con el ratón en Phaser es un proceso muy sencillo, pero por defecto no puedes interactuar con ningún elemento. Si quieres hacerlo, debes llamar al método .setInteractive()
sobre el objeto en cuestión. De esta forma, permitirá al jugador interactuar con ese elemento:
create() {
const robot = this.add.image(x, y, "robot");
robot.setInteractive();
}
Además, el método .setInteractive(hitArea, callback, dropZone)
tiene 3 parámetros opcionales que puedes indicar si quieres personalizar al máximo cuando va a ser interactivo el elemento:
Parámetro | Descripción |
---|---|
hitArea | Forma geométrica que define la zona interactiva personalizada. Por defecto, todo el objeto. |
callback | Función para determinar si el puntero está dentro del hitArea . |
dropZone | false . |
Recuerda que puedes encadenar métodos, de modo que puedes ejecutar el
.setInteractive()
al final del método anterior, como haremos en los siguientes ejemplos.
Escuchar clics en objetos
Una vez hemos establecido como interactivo el elemento con el que queremos interactuar, sólo tenemos que escuchar el evento en cuestión que nos interesa.
Veamos este código completo donde permitimos interactuar con la imagen del robot del juego, tintándolo de rojo cuando pulsamos sobre él (evento pointerdown) y reseteándolo cuando soltamos el botón del ratón (evento pointerup).
Observa especialmente el método de ciclo de vida create()
:
import * as Phaser from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";
const width = 640;
const height = 480;
export class Screen extends Phaser.Scene {
preload() {
this.load.image("robot", `robot.png`);
}
create() {
const [x, y] = [width / 2, height / 2];
const robot = this.add.image(x, y, "robot").setInteractive();
robot.on("pointerdown", (pointer) => robot.setTint(0xff0000));
robot.on("pointerup", (pointer) => robot.clearTint());
}
}
const config = {
type: Phaser.AUTO,
width,
height,
disableContextMenu: true,
autoCenter: Phaser.Scale.Center.CENTER_BOTH,
scene: [ Screen ]
};
const game = new Phaser.Game(config);
Recuerda que el método .setTint()
pinta de un color el objeto, mientras que .clearTint()
lo resetea a su estado original.
Diferenciando el botón de ratón
Como habrás observado en la demo, el ejemplo anterior interactua ante cualquier pulsación de ratón, ya sea con el botón principal, secundario o incluso con el botón central.
Observa esta variación del ejemplo anterior, donde utilizamos el parámetro pointer
para detectar cuál es el botón que se ha pulsado:
create() {
/* ... */
robot.on("pointerdown", (pointer) => {
const isLeftButton = pointer.button === 0;
const isRightButton = pointer.button === 2;
const isMiddleButton = pointer.button === 1;
isLeftButton && robot.setTint(0xff0000);
});
}
De esta forma se puede personalizar la acción a realizar dependiendo del botón pulsado.
Detectar movimiento sobre objetos
Utilizando el evento pointermove
podríamos detectar cuando el usuario está moviendo el ratón sobre un objeto del juego. Recuerda que el evento pointerover
se lanzaría solamente una vez, mientras que pointermove
se lanza continuamente por cada minúsculo movimiento del puntero:
create() {
/* ... */
robot.on("pointermove", (pointer) => {
robot.setTint(Math.random() * 16_000_000);
});
}
Sin embargo, recordemos que en la tabla que vimos antes, habían dos columnas, donde en la segunda teníamos el evento genérico. Este evento es muy útil para realizar una acción sin centrarnos en un objeto concreto. Por ejemplo, observa el siguiente ejemplo donde escuchamos el evento gameobjectmove
sobre this.input
:
create() {
/* ... */
this.input.on("gameobjectmove", (pointer, gameObject) => {
gameObject.setTint(Math.random() * 16_000_000);
});
}
En este caso, escuchamos de forma genérica y el evento se dispararía con cualquier tipo de objeto interactivo. El objeto en cuestión se nos devolvería en el parámetro gameObject
. De esta forma, aunque el código es equivalente al anterior, este último es mucho más flexible y potente en ciertos casos.
Detectar scroll con la rueda del ratón
Utilizando el evento wheel
podemos detectar cuando el jugador realiza un movimiento de la rueda del ratón sobre un objeto del juego:
create() {
/* ... */
robot.on("wheel", (pointer, deltaX, deltaY, deltaZ) => {
robot.scale += deltaY * -0.001;
});
}
Los parámetros deltaX
, deltaY
y deltaZ
nos devuelve información de la cantidad de scroll realizado con la rueda del ratón. Dependiendo del modelo del ratón, es posible que los últimos valores no existan.
Detectar coordenadas del ratón
Es posible que lo que nos interese es saber las coordenadas donde el jugador ha hecho click, para luego realizar nuestros cálculos. En ese caso, debemos utilizar el parámetro pointer
, ya que contiene información de dichas coordenadas, concretamente en las propiedades x
e y
:
create() {
// Coordenadas globales
this.input.on("pointerdown", (pointer) => console.log(pointer.x, pointer.y));
// Coordenadas locales
this.input.on("pointerdown", (pointer, gameObject) => {
const x = pointer.x - (gameObject.x - (gameObject.width / 2));
const y = pointer.y - (gameObject.y - (gameObject.height / 2));
console.log(x, y);
});
}
Observa que en el primer caso, simplemente mostramos los valores de pointer.x
y de pointer.y
. Esto nos devolverá las coordenadas exactas de donde se ha hecho clic en la pantalla del videojuego.
Por otro lado, el segundo ejemplo, está realizando un cálculo para obtener las coordenadas donde se ha pulsado en el propio objeto del juego.