En este artículo vamos a modificar de manera dinámica la velocidad del movimiento de actores del juego atendiendo a su posición. Cambiaremos también la fuerza de la gravedad.
El objetivo final de este juego es realizar un clon del Arkanoid, o el muro, que era el nombre de otro popular juego en España. En este juego la pelota va rompiendo ladrillos y va pasando por diversas pantallas cuando los ha roto todos, ganando poderes, etc.
Obviamente, nos queda bastante trabajo por delante para conseguir acercarnos al objetivo, pero vamos bastante bien. En este artículo nos acercaremos un poco más al objetivo buscado, creando las condiciones adecuadas para la bola y la plataforma, de modo que se comporten como necesitamos para cubrir los aspectos del juego.
Básicamente nos vamos a encargar de estas cosas:
- Manipular la dirección de la bola cuando se producen las colisiones, para que el usuario la pueda dirigir hacia donde desea, haciendo que impacte más a la derecha o la izquierda de la plataforma.
- Ajustar la gravedad del juego, para anularla, ya que no la vamos a necesitar realmente.
- Implementar la posición inicial de la bola, que debería comenzar pegada a la plataforma, hasta que el usuario pulsa la tecla para que salga disparada.
Modificar la dirección y velocidad de la bola
Vamos a conseguir un comportamiento más avanzado en el rebote de la bola, parecido al del clásico Arkanoid.
No sé si recuerdas que la bola se orienta hacia el lugar donde había impactado con la plataforma. Conseguir este efecto es fácil, pero para ello tenemos que volver sobre un punto que ya vimos de pasada en el artículo anterior, que permite analizar la posición de los elementos en el juego.
Averiguar la posición de los elementos del juego
Cada uno de los objetos de la escena en Phaser tiene unas propiedades para saber su posición. Esa posición la podemos obtener con las propiedades "x" e "y" del objeto que nos interesa saber dónde se encuentra.
Nos interesan las posiciones en la horizontal, por tanto, this.ball.x nos dirá la posición de la bola y this.platform la de la plataforma. Si a la posición de la bola le restamos la posición de la plataforma y nos salen valores positivos es que la bola ha impactado en la parte derecha de la plataforma. Si salen valores negativos, es que la bola impactó más a la izquierda y si da cero es que la bola se chocó en el mismo medio.
Una vez sabemos la posición relativa de ambos elementos, podemos modificar la velocidad de la bola a la izquierda o la derecha.
En código este comportamiento podría ser más o menos así.
platformImpact(ball, platform) {
this.score++;
this.scoreText.setText('PUNTOS: ' + this.score);
let relativeImpact = ball.x - platform.x;
if(relativeImpact > 0) {
console.log('derecha!');
ball.setVelocityX(10 * relativeImpact);
} else if(relativeImpact < 0) {
console.log('izquierda!');
ball.setVelocityX(10 * relativeImpact);
} else {
console.log('centro!!');
ball.setVelocityX(Phaser.Math.Between(-10, 10))
}
}
Como puedes ver, los métodos callback de la colisión reciben dos parámetros, que son los objetos involucrados en el choque. Podemos usarlos por facilidad para hacer nuestros cálculos, pero como estamos en un método del objeto, también podríamos haber accedido a estos mismos objetos con this.ball o this.platform.
Ahora nuestra bola cambia el sentido de su bote, según donde haya tocado la plataforma, yendo en una trayectoria más o menos inclinada dependiendo de dónde impactó.
El código hasta el momento lo puedes ver en Github. https://github.com/deswebcom/ball-game-phaser/tree/Comportamiento_colisiones
Eliminar la gravedad del juego
Ahora vamos a hacer un comportamiento ligeramente distinto, que se va a parecer un poco más al juego que intentamos emular, el Arkanoid.
Si lo recuerdas, el Arkanoid comenzaba con la bola pegada a la plataforma y cuando pulsabas un botón, entonces se despegaba y comenzaba a rebotar por la pantalla y romper ladrillos. Las modificaciones que queremos hacer para conseguirlo implican tres porciones de código.
Configuración
El comportamiento del Arkanoid será más fácil si no tenemos gravedad en el juego, ya que si existe gravedad la bola caerá siempre hacia abajo.
Así que vamos a cambiar la configuración inicial del juego para que sea como esta:
const config = {
type: Phaser.AUTO,
width: 800,
height: 500,
scene: [Game],
physics: {
default: 'arcade',
arcade: {
debug: false
}
}
}
Simplemente hemos quitado la configuración de la gravedad.
Forzar el inicio de la bola pegada a la plataforma
Ahora podemos hacer que la bola aparezca pegada en el inicio a la plataforma. Esto se consigue simplemente colocándola de inicio más cerca de la plataforma. Sin embargo, esta modificación implica varios cambios en el código de la escena principal del juego.
Método create()
Comenzamos viendo las configuraciones nuevas en el método create() de la escena del juego.
this.ball = this.physics.add.image(385, 430, 'ball');
Recuerda que en el método create() la plataforma estaba en la posición (400, 460), por lo que la bola ha quedado bastante próxima.
Además vamos a asociar un dato a la bola, para indicar que está pegada a la plataforma:
this.ball.setData('glue', true);
Con el método setData() podemos almacenar valores en distintas claves. En este caso la clave es "glue" y el valor es true. Este dato no modifica en nada el comportamiento de la bola. En realidad tenemos que implementar nosotros este "pegamento". Para ello, tenemos que modificar el método update(). Lo haremos enseguida, pero antes (todavía en el método create()) tenemos que borrar unas líneas de código que hacían que la bola se moviese al principio del juego.
let velocity = 100 * Phaser.Math.Between(1.3, 2);
if (Phaser.Math.Between(0, 10) > 5) {
velocity = 0 - velocity;
}
this.ball.setVelocity(velocity, 10);
Esas líneas las debes borrar del proyecto!
Además en el create() tenemos que agregar una línea que modifica el comportamiento de la plataforma, para que no se salga de los bordes.
this.platform.setCollideWorldBounds(true);
Esta configuración lo cierto es que debería haberse introducido ya al proyecto hace mucho, pero se me había pasado.
Método update()
Recuerda que en update() colocamos todos los comportamientos a ejecutar cuando se usaban los cursores, moviendo la plataforma a cada lado. Ahora tendremos que comprobar si está la bola pegada, en cuyo caso bola y plataforma deben moverse juntas.
Además, vamos a configurar la pulsación del botón de "arriba" del cursor, para que cuando se pulse la bola se despegue y comience el juego.
Todo esto lo tenemos en este método.
update() {
if (this.cursors.left.isDown) {
this.platform.setVelocityX(-500);
if(this.ball.getData('glue')) {
this.ball.setVelocityX(-500);
}
}
else if (this.cursors.right.isDown) {
this.platform.setVelocityX(500);
if (this.ball.getData('glue')) {
this.ball.setVelocityX(500);
}
}
else {
this.platform.setVelocityX(0);
if (this.ball.getData('glue')) {
this.ball.setVelocityX(0);
}
}
if (this.ball.y > 500) {
console.log('fin');
this.gameoverImage.visible = true;
this.scene.pause();
}
if (this.cursors.up.isDown) {
if (this.ball.getData('glue')) {
this.ball.setVelocity(-75, -300);
this.ball.setData('glue', false);
}
}
}
Básicamente, para cada pulsación se comprueba si estaba la bola pegada. Si lo estaba hacemos las acciones correspondientes.
Cuando se pulsa la flecha de arriba del cursor se le asigna una velocidad a la bola y con ello comienza a moverse. Además, en ese momento se modifica el dato "glue", para dejarlo a false y así eliminar el "pegamento" que la unía a la plataforma.
Conclusión
Con estas modificaciones el proyecto ha quedado como puedes ver en el siguiente enlace de Github.
El juego ya tiene bastante sentido y cierta jugabilidad. Podemos comenzar a sentirnos orgullosos de lo que hemos conseguido sin demasiado esfuerzo, ¿qué os parece?
Pero nos queda una parte fundamental, que es colocar los ladrillos que se deben romper con impactos de la bola. Esto nos dará pie a aprender nuevas cosas como es la creación de grupos de elementos en Phaser.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...