Desarrollo de juegos con HTML5 (Primera parte)

En este artículo vamos a aprender cómo hacer el famoso juego de la serpiente. Para seguir el ejemplo es necesario tener conocimientos avanzados de JavaScript. Utilizaremos prototipos para simular una estructura orientada a objetos y HTML5 nos proveerá del canvas para poder desarrollar la acción del juego. Vamos a dividir el ejemplo en dos partes. Primero plantearemos el modelo del juego, dibujaremos lo básico y agregaremos interactividad. Luego, en la segunda parte, agregaremos lo que falta para completarlo.

El ejemplo terminado lo pueden ver aquí.
Y lo que haremos en esta primera parte aquí.
En ambos casos, movemos la serpiente con las teclas: a,w,s,d.

El Juego

Para los que no lo conocen, es un juego para un único jugador, el cual debe controlar una serpiente que se alimenta y que cada vez que lo hace se vuelve más grande. La serpiente avanza constantemente y el jugador sólo puede cambiarle la dirección (horizontal o vertical). Si la serpiente se enrieda, o llega a los bordes del rectángulo de juego, el jugador pierde. El alimento aparece dentro del área de juego de forma aleatoria y el jugador debe conducir a la serpiente hasta ahí para sumar puntos. En cuanto la serpiente come, se hace una unidad más grande.

Juego HTML5

 

Planteo

La serpiente debe moverse en cuatro direcciones y avanzar una unidad a la vez. Esto nos lleva a pensar en cómo definir el mundo sobre el que vivirá y cómo estará representada. La forma de hacerlo es definir una cuadrícula o matriz de cuadrados a la cual se pueda acceder por filas y columnas. El cuadrado será entonces el elemento más pequeño que tendremos. Por lo tanto, para formar parte de ese universo, la serpiente deberá estar formada por cuadrados como así también cualquier otra cosa que aparezca en él. 

Prototipos en Javascript

Antes de empezar a ver el código fuente, les sugerimos que repasen este artículo sobre programación orientada a objetos en Javascript, especialmente el apartado de Extension de objetos nativos mediante el prototipo.

Para conocer más sobre los cambios en el trabajo de clases y objetos a partir de ES6 les recomiendo leer el artículo: Clases en JavaScript con ECMAScript 6.

El código

Vamos a meternos de lleno en el código. Es recomendable ir leyendo el artículo y mirando el código fuente para entenderlo al máximo.
Código fuente de esta primera parte
 

Carga

El juego se carga con el evento onload de window, obtiene el canvas y su contexto los cuales el programa manejará como variables globales. Se instancia la clase Juego y le pasa el control con juego.correr()

Pseudo Clase Juego

Es la clase que controla el flujo del video juego. Tiene una instancia de Serpiente y de <code. A su vez, crea un manejador de eventos para controlar la entrada por teclado. Otro de los atributos que tiene es el intervalo que se usará para realizar el bucle de juego. En este caso, al intentar orientar a objetos esta parte del código nos encontramos con un problema de JavaScript: se pierde la referencia al atributo intervalo, que guarda un identificador para saber a qué intervalo nos estamos refiriendo (hay que pensar que podríamos tener más de uno). Para resolver este problema existen frameworks que hacen más fácil la programación. En este caso, como programamos en JavaScript plano, usamos una técnica no muy elegante tal vez pero que da resultado.

El método iniciarIntervalo hace que el método correr se pueda ejecutar automáticamente cada determinado periodo de tiempo. Es justamente correr el que dibujará los elementos en el canvas, hará las actualizaciones de estados, limpiará y redibujará el canvas

Manejador de Eventos

La habíamos visto en el ejemplo de la nave espacial. Aquí no se usa la sintaxis de prototipos que presentamos al principio, sino la que ya conocíamos. La programación de esta pseudo clase es en realidad un híbrido, no llega a estar totalmente orientada a objetos. Recibe un objeto, pero no lo guarda, sino que simplemente le asigna un evento. Su funcionamiento puede asemejarse más a un método encapsulado en una clase o una función auxiliar. El método tecla captura el evento e invoca al método que corresponde del objeto que recibe, que es la serpiente que ya explicaremos mejor cómo está hecha. Las números que aparecen en el switch se corresponden con las teclas para mover la serpiente (a,s,w,d). 

Cuadro

El universo de nuestra serpiente será una cuadrícula y esta estará formada por cuadrados a los que haremos referencia por fila y columna. Ahora, pensemos; nuestra serpiente vive en un mundo de filas y columnas, sin embargo, el canvas está hecho en píxeles. ¿Cómo hacemos para salvar este problema? La idea es crear una capa de abstracción entre nuestros objetos que viven en el universo cuadriculado y el canvas. Así podremos olvidarnos de los píxeles y trabajar sólo con filas y columnas.

La clase Cuadro se ocupará de dibujar cuadrados en el canvas y estará completamente desacoplada del juego. Es decir, que dibujará cuadrados sin saber si son partes de la serpiente, si es alimento o si es algún otro elemento.

Veamos por dentro la clase. Tiene cuatro atributos: coordenadas cuaX y cuaY de nuestra cuadrícula y por otro lado posX y posY que son las coordenadas reales que corresponden al canvas. Estas dos últimas se calculan en base a las dos primeras. Los cálculos que se realizan sirven para ubicar correctamente el vértice superior izquierdo del cuadrado en el canvas. Cuando se crea un nuevo cuadrado, se le pasa por parámetro qué fila y columna de nuestra cuadrícula queremos que sea. Automáticamente se calcularán posX y posY para luego en caso de invocar a dibujar, puedan verse en el canvas.El método dibujar toma los valores de posX y posY y dibuja el cuadrado. Recibe un parámetro para determinar el color de pintado.

Los métodos getX y getY sirven para averiguar qué posición tiene el cuadrado. Luego vemos que están incDerecha, <codeincArriba, incAbajo y también incIzquierda. Se ocupan de desplazar el cuadrado un lugar en cada una de esas direcciones.
Esta clase nos facilitará todo el trabajo. Ahora podemos crear una serpiente que esté formada por muchos objetos de Cuadro y poder hacer referencia a cada uno de ellos por fila y por columna. 

Serpiente

Por fin hemos llegado a la serpiente. Como acabamos de decir, deberá estar formada por muchos cuadrados. Por lo tanto, tendrá que tener un array de Cuadro. Noten que en la función (pseudo) constructor, se crea el array y se le agrega el primer cuadro que arbitrariamente se ubica en la posición [12,12] de la cuadrícula. También deberá tener una dirección, que se inicializa en esta misma función.

Hasta esta primera parte del ejemplo, el cuerpo de la serpiente será de un único Cuadro, luego en la segunda parte le agregaremos más. El método dibujar recorre el array con el cuerpo y lo dibuja. En este caso, dibuja un único cuadrado. El método avanzar hace desplazar un lugar ese cuadro en la dirección que corresponde.

El método cambiarDir simplemente actualiza la dirección de la serpiente, es invocada desde el manejador de eventos cuando el usuario presiona una tecla. getposX y getposY obtiene la posición de la cabeza de la serpiente y servirá luego para chequear dónde está y si chocó contra algo. 

Mundo

La clase mundo está de forma simbólica en este ejemplo puesto que en realidad no entra en juego con los otros objetos. Pero es importante ver que la entidad Mundo podría definir dentro algunos elementos como por ejemplo obstáculos para la serpiente. Aquí simplemente se definieron los límites de la cuadrícula y un método que se encarga de dibujar líneas para que se vean los cuadrados que forman la cuadrícula.

Hasta aquí tendremos un cuadrado que se desplaza por la cuadrícula y al cual le podemos cambiar la dirección. En la segunda parte terminaremos el ejemplo y completaremos la serpiente.

Más sobre Diseño y desarrollo Web


Desarrollador apasionado por las tecnologías web, con experiencia en lenguajes (x)HTML, CSS, PHP, Java, Javascript, AJAX y MySQL. También en sistemas de publicación CMS como WordPress y frameworks como Code Igniter. Además se especializa en sistemas GNU/Linux siendo también un difusor del Software Libre. En el ámbito laboral se desempeñó como programador web, webmaster y como administrador de sistemas llevando adelante procesos de migración a Software Libre. Estudia la carrera de Licenciatura en Análisis de Sistemas en la Facultad de Ingeniería de la UBA y se desempeña como programador freelance.

3 Comentarios en “Desarrollo de juegos con HTML5 (Primera parte)

  1. Jesus dice:

    El juego me carga pero no lo puedo mover con las teclas w,s,a,d…. la serpiente no se mueve, lo he probado en todos mis navegadores y no funciona… ¿ por qué podrá ser ?

    • tury dice:

      Hola Jesús

      El ejemplo se programó para Google Chrome en su versión 14. Hemos comprobado su correcto funcionamiento en Opera y Safari. En Firefox ocurre justamente lo que comentas. Y esta es la explicación:

      Existe una incompatibilidad en la captura de eventos en los distintos navegadores. Esto no es nuevo, de hecho viene desde hace unos años y es totalmente ajeno a HTML5.
      Hay algunas formas de salvar estos problemas de incompatibilidad en la captura de eventos, pero que de incluirlos haríamos más extensa la explicación y nos desviaríamos del objetivo del artículo que es cómo combinar la POO con el Canvas de HTML5 para desarrollar videojuegos. Para más información sobre la captura de eventos en Firefox, te recomiendo visitar la web de Mozilla para desarrolladores

      Por otra parte, esta incompatibilidad es un problema más que se suma a la complejidad de desarrollar utilizando Javascript plano, como decimos en la conclusión del artículo.

      No sé en que navegadores has hecho la prueba, pero te recomiendo que pruebes este ejemplo y cualquier otro de nuestro sitio primero en Google Chrome ya que es nuestro navegador predilecto a la hora de desarrollar.

      Agradezco tu comentario y tu participación.

      Saludos
      Alejandro

    • Damian dice:

      Hola Jesus!

      Muchas gracias x tu participación en el sitio. Quería agregar algo al margen de lo que te comenta Alejandro sobre el tema de eventos con Firefox y el enlace que te pasa para que veas como se puede mejorar la compatibilidad en ese sentido. Y es que con HTML5 se introducen muchas características características que se están haciendo compatibles de apoco en los diferentes navegadores.

      Canvas es una de estas características y si bien en las últimas versiones de los navegadores se está agregando, el grado de compatibilidad con algunas funciones puede variar, ya que es una API que está actualmente en Draft (en estado de desarrollo) por el grupo de trabajo.

      Sobre todo el tema de compatibilidad, especificamente hablando de HTML5 y de sus APIs relacionadas, te recomiendo que pruebes Modernizr (http://www.modernizr.com/download/). Este framework te permitirá detectar la compatibilidad del navegador para decidir que mostrar, en caso de alguna incompatibilidad con las características que estés intentando implementar.

      Te mando un gran abrazo y gracias por tu comentario.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*