Saltar al contenido →

Diario Breakout – Parte 5 y ¿última?

En esta quinta parte de la serie de artículos Diario Breakout, explicaré los últimos retoques y añadidos que he hecho al juego. He añadido algunos sonidos, un gestor de niveles (y una forma de crearlos más cómoda) además de varios niveles y una serie de poderes especiales (power-up) positivos y negativos. Finalmente, he conseguido una versión jugable del juego.

Agregando sonidos

Lo primero que hice fue decidirme por utilizar una librería externa. El caso del audio en HTML5 está todavía un poco verde y no está pensado para ser utilizado en juegos al origen sino para reproducir sonidos. Por eso, preferí utilizar una librería externa que se encargue de gestionar todos los problemas con los que me iba a encontrar seguramente. Finalmente he elegido howler.js. Más sencillo de utilizar, imposible. Esto es el código que he tenido que agregar a mi clase «Game».

El método loadSounds carga los sonidos en memoria. Creo un objeto Howl al cual paso el lugar donde está el sonido y  pongo el flag de autoplay a false para que no se reproduzca automáticamente por defecto al cargar. Este método se llama sólo una vez en la inicialización del juego, el método «initialize».

El método playSound, como su nombre indica, reproduce el sonido. Le paso el nombre del sonido a reproducir y llamo al método play() de la librería howler.js. Este método se llama desde varios lugares:

  • El método «lose», cuando se pierde una vida.
  • El método «gamewin», cuando se gana el juego.
  • El método «checkCollisions» de la clase «Ball», cuando la bola choca con un bloque.

Los sonidos han sido descargados de Freesound.org, salvo el del choque bola-bloque que lo creé con el programa Bfxr.

Creación de niveles y gestor de niveles

Hasta ahora sólo tenía un nivel y la creación de este nivel era muy tediosa. Siguiendo la misma idea que jakesgordon, he simplificado la forma de crear niveles lo que hará mucho más sencillo crearlos. Además, he añadido dos tipos de bloques distintos que la única diferencia que tendrán es que serán más resistentes. A partir de ahora existirán 3 tipos de bloques:

  • El bloque verde que será destruido al primer golpe.
  • El bloque blanco que será destruido al segundo golpe.
  • El bloque azul-verde  que será destruido al tercer golpe.

Para que el usuario sepa en qué punto está cada bloque, irán cambiando de color. El bloque azul-verde cambiará a color blanco cuando lo golpeen una vez y a color verde cuando lo golpeen la segunda vez. Como ya tenía en la clase «Brick» un atributo «life», no he tenido que hacer grandes cambios. Ese atributo contendrá la vida que le resta al bloque, cuantos golpes serán necesarios para destruirlo (1, 2 o 3). Irá disminuyendo con cada golpe y cada vez que el método «hit» es llamado, cambiará de color según la vida que le resta.

En cuanto a los niveles, he creado un método «startLevel» en la clase «Game». Este método contiene parte del código que tenía antes en el método «startGame». Esto es lo que hace:

  • Cambia el estado del juego a GAME_PLAYING.
  • Oculta el menú.
  • Crea una bola.
  • Crea la pala.
  • Inicializa el array de poderes especiales (más tarde hablaré sobre esto).
  • Inicializa el array de bloques.
  • Recorre el nivel en el que estamos y crea los bloques en las posiciones correctas.

Este es el método «startLevel»:

Para los niveles, he creado un archivo json en la que iré almacenando todos los niveles. Este es el contenido del archivo levels.js.

Este archivo contiene un sólo objeto Levels que es un array de objetos. En cada objeto, tendremos un array de cadenas llamado bricks que funcionará de la siguiente forma:

  • He dividido el canvas en filas y columnas. Cada bloque será de 24px de ancho por lo que habrá como máximo 15 bloques por fila. Existirán unos píxeles de espacio a cada lado entre el borde del canvas y el primer y último bloque de cada fila.
  • Si la cadena es vacía, la fila del canvas será vacía. No tendrá ningún bloque y pasaremos a la siguiente fila.
  • Si la cadena no es vacía, pasaremos a comprobar su contenido carácter a carácter. Si es un espacio, no pondremos bloque y saltaremos a la siguiente columna.
  • Si el carácter es un 1, se colocará un bloque verde, es decir que será destruido con un sólo golpe.
  • Si el carácter es un 2, se colocará un bloque blanco, destruido con dos golpes.
  • Si el carácter es un 3, se colocará un bloque azul-verde, destruido con tres golpes.

De esta forma, es relativamente sencillo crear niveles, para esta demo, he creado sólo 3 niveles.

Los poderes especiales o Power-Ups

Los poderes especiales son los que aportan un poco de emoción al juego y lo hacen menos aburrido. Para crear los poderes, he tenido que crear una nueva clase: la clase «Power». Este es su contenido:

El constructor almacena la posición (x,y) y el tamaño (width, height) además de guardar el tipo del poder (type) y el estado (hidden). Cuando el poder está oculto (hidden=true), el poder no está liberado y por lo tanto permanece «dormido». Sólo cuando el bloque que lo contiene sea destruido, el poder será liberado (hidden=false) y empezará a caer hasta que supere los límites del canvas o la pala colisione con él.

Según el tipo de poder que sea, tendrá unos atributos distintos. Estos son los poderes que he creado:

  • POWERUP_BIGGER: Este poder aumenta el tamaño de la pala. Dará 10 puntos al jugador si lo recoge. Tendrá una velocidad de 1px por ciclo.
  • POWERUP_EXTRABALL: Este poder creará otra bola en el canvas y el jugador tendrá que jugar con más de una bola. Dará 50 puntos al jugador si lo recoge. Tendrá una velocidad de 2px por ciclo.
  • POWERDOWN_SMALLER: Este poder disminuye el tamaño de la pala. Es un poder «negativo» que complica la vida al jugador, por lo tanto se le dará 100 puntos si lo recoge. Tendrá una velocidad de 0.5px por ciclo. Al hacerlo tan lento, su tiempo en pantalla será mucho mayor, lo que aumenta las posibilidades de que el usuario tenga que cogerlo sin remedio y la dificultad del juego.
  • POWERUP_LIFE: Este poder otorgará una vida extra al jugador. Sólo dará 10 puntos ya que la vida extra es suficiente premio. Su velocidad será de 3px por ciclo lo que hará más complicado capturar este poder.

La clase tiene 4 métodos a mayores:

  • El método «draw» que es más de lo mismo. Un poder será parecido a un bloque normal pero con un borde y un fondo de otro color. Será más fácil diferenciarlo. Si el poder está oculto, no se hará nada.
  • El método «update» actualiza la posición del poder, en concreto sólo actualizará el valor de la coordenada y. El poder sólo irá hacia abajo en línea recta. Además, si el poder está oculto, no hará nada.
  • El método «release» es la liberación del poder que lo único que hace es poner el valor de hidden a false.
  • El método «hit» gestiona el hecho de que la pala colisione con el poder. Según el tipo del poder, se realizará una acción u otra además de actualizar la puntuación del usuario.

En la clase «Game», la aparición de los poderes se traduce en varios cambios. Los poderes irán asociados a un bloque, por lo tanto cada vez que se crea un bloque se intentará crear un poder. Para eso, he puesto un sistema de probabilidades que irá aumentando a medida que haya más bloques. Este es el código del método «tryCreatePower»:

Este método recibe como argumento el bloque al que se asociará el poder si se crea y el número total de bloques. Primero compruebo si no he llegado al máximo de poderes positivos. Después, con la función Math.random() de javascript, que me devuelve un valor entre 0 y 1, buscaré un valor que sea menor que la probabilidad que haya fijado para crear poderes positivos en este caso yo he puesto 0,01. Puede parecer bajo pero como multiplico este valor por el número total de bloques, este valor se irá incrementado y hará más sencillo que los poderes aparezcan cuantos más bloques existan. He hecho esto porque sino la mayoría de los poderes aparecían en los primeros bloques y poco repartidos. En el caso del poder negativo el sistema es el mismo. Si consigo un valor suficiente para crear un poder, genero el tipo del poder aleatoriamente, creo el objeto «Power», lo guardo en el array de poderes, aumento el valor de poderes para saber cuantos tengo en total y devuelvo el objeto para que sea asignado al bloque.

En la clase bloque he añadido tres nuevos métodos que gestionaran los poderes:

El método «addPower» asocia el poder pasado como parámetro al bloque actual.

El método «hasPower» devuelve verdadero o falso según si el bloque actual tiene un poder asignado o no.

El método «releasePower» libera el poder. Este método es llamado cuando el bloque es destruido y llama al método «release» de la clase «Power» lo que hace que el poder ya no es oculto y se mueve.

¿Fin de Diario breakout?

Y con todo esto, el juego ahora es un juego como dios manda. Un menú, Game Over, poderes especiales, varios niveles, sonidos, … Podría añadir muchas más cosas, más niveles, gráficos, más sonidos, más poderes, listado de puntuaciones. Probablemente lo haga en el futuro pero para ser un comienzo creo que es más que suficiente y puedo pasar a otro tipo de juegos y seguir investigando. Como siempre os dejo la demo colgada para que podáis ver el código completo.

Aquí tenéis el enlace de la demostración: VER DEMO

Algunas de las fuentes que he utilizado:

Este artículo forma parte de una serie:
  1. Introducción: Another Breakout game…
  2. Diario Breakout – Parte 1
  3. Diario Breakout – Parte 2
  4. Diario Breakout – Parte 3
  5. Diario Breakout – Parte 4
  6. Diario Breakout – Parte 5 y ¿última?
  7. Diario Breakout – Integrar Clay.io

He subido Breakout a GitHub.

Prueba la versión final.

Share