Acierta imagen en PhaserJS

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

El siguiente juego que haremos consiste en seleccionar en un tiempo limitado la imagen que es igual a la imagen que aparece en grande en la parte superior de la escena. Al acertar la imagen, se mostrará otra diferente e incrementaremos un marcador de puntos. Si fallamos, iremos a la escena de partida perdida.

Pasos en la resolución del juego de acierta imagen con PhaserJS

Carga fondo

En la escena principal del juego, Game.js, cargamos la imagen de fondo que habremos precargado previamente en el Boot.js.

create() {
	this.add.image(0, 0, "back").setOrigin(0, 0);
}

Carga caras

A continuación cargamos las caras que se verán en cada uno de los televisores que aparecen en la fila inferior.

create(){
	this.face0 = this.add.sprite(225, 425, 'face0').setScale(0.5, 0.5);
	this.face1 = this.add.sprite(480, 460, 'face1').setScale(0.5, 0.5);
	this.face2 = this.add.sprite(740, 425, 'face2').setScale(0.5, 0.5);
}

Cara pulsada

Queremos que las caras de los televisores reaccionen a nuestra pulsación sobre ella. Por tanto, hacemos cada cara susceptible de ser pulsada (utilizando setInteractive), y les añadimos el evento pointerdown, que llamará a la función clickedFace que mostrará un mensaje de alerta indicando que imagen hemos pulsado.

create(){
	...
        this.face0.setInteractive().on('pointerdown', () => this.clickedFace(this.face0));
	this.face1.setInteractive().on('pointerdown', () => this.clickedFace(this.face1));
        this.face2.setInteractive().on('pointerdown', () => this.clickedFace(this.face2));
}

clickedFace(face) {
	alert(face.texture.key);
}

Caras aleatorias

En la fila inferior no siempre aparecerán las mismas imágenes. Para aleatorizarlas he desordenado un array con tantos números como imágenes hay disponibles. Desordeno el array y utilizo los tres primeros números (que ahora serán aleatorios), para concatenarlos con el nombre del sprite que queremos cargar.

create(){
	...
	newTurn();
}

newTurn(){
	const numbers = [0, 1, 2, 3, 4, 5, 6];
	this.randomizeArray(numbers );
	
	this.face0.setTexture(`face${numbers [0]}`);
	this.face1.setTexture(`face${numbers [1]}`);
	this.face2.setTexture(`face${numbers [2]}`);
}

randomizeArray(array) {
	return array.sort(() => Math.floor(Math.random() * 3) -1);
}

Imagen solución random

La imagen del televisor superior también debe ser aleatoria. El siguiente código utiliza una de las imágenes obtenidas en el paso anterior para pasársela al televisor superior.

create(){
	...
	this.spriteSolution = this.add.sprite(470, 190, 'face0');
}

newTurn(){
	...
	const choosedFace = 'face' + numbers[Math.floor(Math.random() * 3)];
	this.spriteSolution.setTexture(choosedFace);
}

Evalúa solución

Al pulsar en una de las caras de la fila inferior debemos evaluar si la cara pulsada coincide con la cara que se muestra en el televisor superior de la pantalla. Si coinciden, mostraremos el texto éxito y si no fracaso.

clickedFace(face) {
	if (face.texture.key === this.spriteSolution.texture.key) {
		alert('éxito');
	} else {
		alert('fracaso');
	}
}

Marcador

Para cargar una tipografía externa en nuestro proyecto:

<style>
    @font-face {
        font-family: font1;
        src: url('/redkost-comic.otf');
        font-weight:400;
        font-weight:normal;
    }
</style>
<div style="font-family:font1;position: absolute;left: -1000px;visibility: hidden;">.</div>

Para hacer el marcador, podemos crear dos objetos. Uno que será el texto que mostraremos por pantalla (this.scoreTXT) y otro que será una variable que se incrementará cuando el usuario acierte(this.score).

create() {
	...
	this.score = 0;
	this.scoreTXT = this.add.text(90, 120, this.score, {
	    fontFamily: 'font1',
	    fontSize: 60,
	    color: '#00ff00',
	    align: 'right'
	});
	this.scoreTXT.setOrigin(1, 0);
}

El siguiente código establece el nuevo marcador cada vez que el usuario acierta

++this.score;
this.scoreTXT.setText(this.score);

También es interesante que creemos un nuevo objeto de texto para mostrar la palabra pts (puntos) al lado del objeto del marcador de puntos.

this.add.text(105, 150, 'pts', {
    fontFamily: 'font1',
    fontSize: 24,
    color: '#00ff00'
});

Temporizador

El jugador tendrá un tiempo limitado para seleccionar la solución correcta. Controlaremos este tiempo con la variable this.timing. Esta variable irá decrementándose a cada segundo. Para ello, llamaremos a la función timer() utilizando this.time.delayedCall. Esta función recibe como parámetro de entrada el margen de tiempo (1000 milisegundos en nuestro caso) con el que iremos llamando a la función this.timer.

Además de modificar la variable this.timing, la función timer(), va a utilizar el nuevo valor de de this.timing para actualizar el monitor de tiempo que tenemos en pantalla (this.timeTXT). Cuando el tiempo se agote (this.timming === 0), mostraremos un mensaje de alerta.

create(){
    ...
    this.timeLimit = 10;
    this.timing= this.timeLimit ;
    this.timeTXT = this.add.text(835, 130, this.timing, {
        fontFamily: 'font1',
        fontSize: 64,
        color: '#00ff00',
    });
    this.timeTXT.rotation = 20*Math.PI/180;
    this.timer();
}

timer() {
    --this.timing;
    this.timeTXT.setText(this.timing);
    if (this.timing=== 0) {
        alert('Se acabó el tiempo');
    } else {
        this.time.delayedCall( 1000, this.timer, [], this);
    }
}

Si acertamos la imagen, vamos a resetear el tiempo para que vuelva a comenzar en 10 segundos.

clickedFace(face) {
    if (face.texture.key === this.spriteSolution.texture.key) {
        ...
        this.timing = 10;
        this.newTurn();
    }
    ...
}

Escena de perder

En el caso de que el tiempo se agote o que el jugador seleccione una opción incorrecta, cargaremos la escena de partida perdida.

class GameOver extends Phaser.Scene {
    constructor() {
        super('GameOver');
    }

    create() {
        this.add.image(0, 0, "lose").setOrigin(0);
        this.input.on("pointerdown", () => this.scene.start("Game"), this);
    }
}

export default GameOver;

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