Actualización sobre la versión 1.0 anterior en la que se ha corregido un error, cambiado el uso del teclado por el del ratón y añadido más niveles de juego.

Modificaciones realizadas

Resumen de las modificaciones realizadas en el código fuente JavaScript de la versión 1.0 del juego Arkanoid para obtener la versión 1.1:
– Cambiado el uso del teclado por el uso del ratón
– Corregido un error en la detección de colisiones de la paleta
– Añadidas tres vidas por partida
– Añadidos tres niveles al juego
– Añadido control del tiempo durante el cual se muestran los mensajes informativos

Arkanoid
¡Jugar!
(abre una nueva ventana)
Actualización: Existe una nueva y mejorada versión 1.2

Código fuente

Al ser un programa escrito completamente en JavaScript, todo el código fuente se encuentra embebido dentro de la propia página HTML desde la que se ejecuta el juego, por lo que para acceder al mismo basta con seleccionar la opción «ver código fuente de la página» del navegador.

Uso del Ratón en JavaScript

Una de las mejoras más importantes realizadas en esta nueva versión del juego ha sido la de cambiar el uso del teclado por el del ratón. Con este cambio se ha mejorado significativamente la jugabilidad, eliminando el problema del retardo en el tiempo de respuesta del teclado que hacía que la paleta resultara dificil de controlar.

El control del ratón a través de JavaScript se realiza de forma muy similar al del teclado. Basta con indicarle a JavaScript el nombre de la función que se quiere que se ejecute cuando se produzca un evento generado por el ratón. Entendiendo por evento de ratón alguna acción que se realiza con el mismo, como moverlo o pulsar uno de sus botones.

Las modificaciones realizadas al código fuente del juego no han sido muchas. La primera de ellas ha sido el añadir, dentro del método run de la clase Game, una llamada al método de registro del ratón:

    self.registerMouse();

El método registerMouse, muy similar a registerKeyBoard, asigna el método onMouseMove de la clase al atributo onmousemove de la página web:

  this.registerMouse = function() {
    document.onmousemove = self.onMouseMove;
  }

De esta forma se consigue que cada vez que el ratón se mueva sobre la página web JavaScript llame automáticamente al método onMouseMove:

  this.onMouseMove = function(e) {
    switch(self.state) {
      case 2:
      case 3:
        self.board.onMouseMove( self.getClientX(e), self.getClientY(e) );
        break;
    }
  }

El método onMouseMove, de igual forma que onKeyDown para el teclado, se limita a comprobar el estado en que se encuentra el juego y reenviar el evento a la clase Board si hay una partida en curso.

La forma de obtener las coordenadas concretas a las que se ha movido el ratón varía dependiendo del navegador que se está utilizando. En Firefox se reciben como un par de atributos (pageX, pageY) dentro del evento pasado como parámetro, mientras que en Internet Explorer hay que examinar el par de valores (clientX, clientY) de la variable global window.event:

  this.getClientX = function(e) {
    return(e? e.pageX: window.event.clientX);
  }
 
  this.getClientY = function(e) {
    return(e? e.pageY: window.event.clientY);
  }

Movimiento de la paleta

El cambio de teclado a ratón ha implicado tener que cambiar la manera en la que se mueve la paleta. Ahora, en vez de recibir los eventos en onKeyDown, los recibe en un nuevo método llamado onMouseMove. Este método recibe la posición del ratón y la compara con la posición actual de la paleta, si la posición del ratón es mayor que la de la paleta entonces se mueve la paleta hacia la derecha, y si es menor se mueve hacia la izquierda:

  this.onMouseMove = function(clientX, clientY) {
    if (clientX - this.left > this.speed)
      this.move(this.speed);
    if (clientX - this.left < this.speed)
      this.move(-this.speed);
  }

En esta nueva versión del juego además se ha corregido un error en el movimiento de la paleta que hacía que a veces esta se solapase con la pelota atrapándola en su interior. Un error debido a que al mover la paleta no se comprobaba si en su nueva posición ya se encontraba la pelota. Para resolverlo se ha añadido un método llamado checkHitBall a la clase Board que se llama por cada posición intermedia por la que debe pasar la paleta para llegar de su posición actual a su posición final:

  this.move = function(speed) {
    var left    = this.left;
    var newLeft = this.left;

    var deltaLeft = this.getNewLeft(speed) - this.left;
    var delta     = Math.abs(deltaLeft);

    for (var i = 0; i < delta; ++ i) {
      left += (deltaLeft / delta);
      if ( this.board.checkHitBall(left, this.top, this.width, this.height) ) {
        break;
      }
       
      newLeft = left;
    }

    this.moveLeft(newLeft);

  }

Vidas y Niveles

Para hacer el juego un poco más largo se han añadido tres vidas por partida y tres niveles con ladrillos de distintos colores.

El número de vidas disponibles en cada momento lo que controla la clase Game, a la que se ha añadido un nuevo atributo lives:

  this.lives = 3;

Y el nivel actual en juego lo controla la clase Board, a la que se ha añadido un nuevo atributo level:

  this.level = 1;

Para controlar el número de vidas y pasar de nivel se ha cambiado el bucle principal de control del juego que está en el método onTimerGame:

  this.onTimerGame = function() {
    self.help.onTimer();
    self.board.onTimer();
    self.score.addToScore( self.board.getPoints() );
    self.board.removeBroken();
   
    if ( self.board.bricksOut() )
      self.board.nextLevel();
     
    if ( self.board.ballOut() ) {
      -- self.lives;
      if (self.lives == 0) {
        self.stop();
      }
      else {
        self.state = 3;
        self.timeEvent = new Date().getTime();
      }
    }
  }

Ahora cuando el número de ladrillos se termina se cambia de nivel con el método nextLevel de la clase Board. Y cuando la pelota se sale por debajo del tablero se resta una vida del atributo lives. Cuando el número de vidas llega a 0 se acaba la partida. Con el atributo timeEvent se realiza una pequeña pausa cuando se pierde una vida que da tiempo a mostrar el número de vidas que quedan y generar una nueva pelota.

  this.nextLevel = function() {
    this.level ++;
    if (this.level > 3)
      this.level = 1;
   
    this.destroyBall();
    this.createBricks();
    this.createBall();
    this.display();
  }

El método createBricks llamado desde nextLevel se ha cambiado para que llame a la función de creación de ladrillos adecuada en función del nivel en el que se encuentra el juego. Para hacer esto se ha aprovechado la peculiar forma que tiene JavaScript de tratar a los elementos de una clase como si todos fueran parte de un array asociativo. Construyendo asi en tiempo de ejecución el nombre de la función a la que se tiene que llamar:

  this.createBricks = function() {
    this["createBricks" + String(this.level)]();
  }

Los métodos createBricks1, createBricks2 y createBricks3 generan mediante código los ladrillos que conforman cada uno de los niveles del juego. El código de estos métodos se reduce a simples bucles en los que se van creando y añadiendo elementos HTML del tipo div a la página web.

Control de tiempo en los mensajes

La última modificación reseñable en el código fuente del juego ha sido añadir un control sobre el tiempo total durante el cual se muestra un mensaje en el borde inferior del tablero.

Se ha añadido un nuevo método a la clase Help que borra automáticamente los mensajes mostrados cuando han trancurrido más de 4 segundos desde que se mandaron a imprimir.

  this.onTimer = function() {
    var currentTime = new Date().getTime();
    if (currentTime - this.timeDisplay > 4000) {
      this.display("");
    }
  }