Crea tu primer videojuego con HTML5

La mayoría de nosotros tiene grandes ideas para hacer nuevos videojuegos. Desgraciadamente son pocas las personas que hacen realidad dichas ideas porque la mayoría piensa que programar juegos es algo muy difícil. En realidad, programar juegos no es algo tan complicado; si tienes conocimientos básicos de HTML, CSS y Javascript, es suficiente para que puedas comenzar a hacer tus primeros juegos.

Agrega un elemento Canvas a una página web

Una de las características más atractivas de HTML5 es el elemento <canvas>, que puede utilizarse para dibujar gráficas vectoriales y generar efectos visuales, juegos interactivos y animaciones. Un Canvas es un área rectangular que permite el despliegue (rendering) dinámico de gráficas 2D. El Canvas interactúa con CSS3 y Javascript para generar gráficos y animaciones interactivas en el navegador web, sin necesidad de plugins. El listado 1 contiene el código básico para definir un Canvas.

<body onload="spaceShipGame()">
<h1>SpaceShipGame</h1>
<canvas id="spaceCanvas" width="300" height="300">
</canvas>
</body>

Listado 1. Canvas

Esto es muy similar a como se define una imagen con el elemento <img>, con la diferencia de que no tiene los atributos src y alt. El elemento <canvas> solamente tiene dos atributos: width (ancho) y height (alto), ambos tienen un valor default de 300 pixeles. El valor del id se utiliza para interactuar con el Canvas por medio de Javascript.

Dibuja los gráficos

El listado 2 muestra el código para crear un fondo negro con estrellas blancas.

// Obtenemos una referencia al canvas.
canvas = document.getElementById("spaceCanvas");
ctx = canvas.getContext("2d");

// Lo pintamos negro
ctx.fillStyle = "black";ctx.rect(0, 0, 300, 300);
ctx.fill();

// Dibujamos 100 estrellas blancas
ctx.fillStyle = "white";
for (i = 0; i <= 100; i++) {    
// Generamos coordenadas al azar entre 20 y 299     
var x = 20 + Math.floor(Math.random() * 279);     
var y = 20 + Math.floor(Math.random() * 279);
   // Dibujamos la estrella    
ctx.beginPath();    
ctx.arc(x, y, 3, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
}

Listado 2. Imagen de fondo con estrellas

Primero obtenemos una referencia a nuestro elemento Canvas y luego obtenemos su contexto. Este objeto nos provee métodos para poder manipularlo.

Para crear las estrellas utilizamos la función “arc”, que se utiliza para crear círculos (parciales o completos). En este caso estamos creando círculos en las coordenadas “x, y” con un radio de 3 pixeles, comenzando el trazo en el ángulo 0 y terminando en el ángulo 2Pi (es decir que es una circunferencia completa).

Notarán que los valores de nuestras coordenadas deben ser mayores a 20,20. Esto es para dejar espacio para nuestra nave espacial, que iniciará en la esquina superior izquierda.

Para pintar nuestra nave utilizaremos curvas de bezier por medio de la función “bezierCurveTo”. Esta función recibe 6 valores como parámetro, que en realidad son 3 pares de coordenadas: los primeros 2 pares de coordenadas son puntos de control y el último par es el punto final. El listado 3 muestra el código para dibujar nuestra nave.

function nave() {
// Dibujemos la nave usando curbas de bezier.
// Primero pintemos el fuselaje en azul
ctx.fillStyle = "rgb(0, 0, 255)";
ctx.beginPath();
ctx.moveTo(28.4, 16.9);
ctx.bezierCurveTo(28.4, 19.7, 22.9, 22.0, 16.0, 22.0);
ctx.bezierCurveTo(9.1, 22.0, 3.6, 19.7, 3.6, 16.9);
ctx.bezierCurveTo(3.6, 14.1, 9.1, 11.8, 16.0, 11.8);
ctx.bezierCurveTo(22.9, 11.8, 28.4, 14.1, 28.4, 16.9);
ctx.closePath();
ctx.fill();

// ahora la cabina en rojo
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.beginPath();
ctx.moveTo(22.3, 12.0);
ctx.bezierCurveTo(22.3, 13.3, 19.4, 14.3, 15.9, 14.3);
ctx.bezierCurveTo(12.4, 14.3, 9.6, 13.3, 9.6, 12.0);
ctx.bezierCurveTo(9.6, 10.8, 12.4, 9.7, 15.9, 9.7);
ctx.bezierCurveTo(19.4, 9.7, 22.3, 10.8, 22.3, 12.0);
ctx.closePath();
ctx.fill();
}

Listado 3. Nave espacial

Al ver nuestro código en un navegador, veremos una imagen similar a la de la figura 1.

android-html5-spaceship.png

Figura 1. Imagen inicial

Agrega comportamiento

Ahora vamos a mover la nave espacial usando Javascript. Cada movimiento se hace en dos pasos:

  1. Borramos la nave de su posición actual (reestableciendo el fondo que había en el lugar donde dibujamos la nave).
  2. Dibujamos la nave en su nueva posición.

Estas serán las dos actividades que realizaremos de manera continua para estar redibujando la nave. El listado 4 muestra como lo implementamos.

function gameLoop() {
ctx.putImageData(oldBackground, oldX, oldY);
ctx.putImageData(ship, newX, newY);
}

Listado 4. Ciclo para redibujar la nave

Como podrán ver, en el listado 4 aparecen variables que no habíamos definido. Estas son variables que utilizamos para almacenar: las coordenadas anteriores de la nave, las coordenadas nuevas, un objeto con la imagen de la nave, y un objeto con la imagen de fondo anterior (para reestablecerlo cuando movamos a la nave a otro lugar). Más adelante veremos como se inicializan y actualizan dichas variables.

Para definir que queremos que nuestra función “gameLoop” se esté ejecutando de manera continua utilizamos el método setInterval() de esta forma:

setInterval(gameLoop, 20);

es decir que cada 20 milisegundos se ejecutará la función gameLoop.

A continuación vamos a capturar el evento cuando alguien toca la pantalla y moveremos la nave a dicho lugar. Para ello, registramos el evento “touchstart” y definimos una función que realice las acciones correspondientes. El listado 5 muestra el código.

document.addEventListener("mousedown", moverNave, true);
function moverNave (event) {
event.preventDefault(); //Para evitar el comportamiento default
oldX = newX;
oldY = newY;
oldBackground = newBackground;
ctx.putImageData(oldBackground, oldX,oldY);
var eventTouch;
eventTouch = event.changedTouches[0];
newX = eventTouch.pageX - 15;
newY = eventTouch.pageY - 60;
newBackground = ctx.getImageData(newX, newY, 30, 30);
}

Listado 5. Registrar evento y actualizar variables de control.

Lo primero que hacemos en esta función es llamar el método preventDefault() del evento, para evitar que se dispare el comportamiento default para dicho evento.

Posteriormente actualizamos nuestras variables de control para almacenar las coordenadas e imagen de fondo actual, y procedemos a borrar la nave (poniendo el fondo que tenemos almacenado para esa posición).

Después registramos las coordenadas donde se dio el evento táctil y guardamos la imagen de fondo que se encuentra en el recuadro para las nuevas coordenadas (antes de que se redibuje la nave ahi). Al guardar las nuevas coordenadas, se darán cuenta que estamos restando 15 a la X y 60 a la Y. Esto es tan solo un ajuste para buscar que la nave quede más centrada a donde hicimos el tacto.

Es importante notar que en realidad en esta función no estamos dibujando la nave, solo actualizamos las coordenadas. Como ya vimos, la función que se encarga de estar redibujando la nave es gameLoop, usando la información de las coordenadas almacenadas.

El listado 6 contiene el código completo de este ejercicio. Puedes salvarlo como archivo html, y accederlo desde el navegador web de tu dispositivo móvil para probarlo. También está disponible como un gist por si quieres clonarlo en https://gist.github.com/pedrogk/9352563

<!DOCTYPE html>
<html>
<head>
<title>Nave espacial</title>
</head>
<body>
<h1>Juego de nave espacial</h1>
<canvas id="spaceCanvas" width="300" height="300">
</canvas>
</body>
</html>
<script>
canvas = document.getElementById("spaceCanvas");
ctx = canvas.getContext("2d");

// definimos variables para almacenar imagenes que usaremos.
var oldBackground;
var newBackground;
var ship;

// definimos e inicializamos variables para coordenadas.
var oldX = 0;
var oldY = 0;
var newX = 0;
var newY = 0;

fondo();
nave();
setInterval(gameLoop, 20);
document.addEventListener("touchstart", moverNave, true);

function fondo() {
// Primero lo pintamos negro
ctx.fillStyle = "black";
ctx.rect(0, 0, 300, 300);
ctx.fill();

// Dibujemos 100 estrellas
ctx.fillStyle = "white";
for (i = 0; i <= 100; i++) {
// Generamos coordenadas al azar entre 30 y 299
var x = 30 + Math.floor(Math.random() * 269);
var y = 30 + Math.floor(Math.random() * 269);

// Dibujamos la estrella
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
}
// inicializamos la imagen de fondo con el estado inicial
newBackground = ctx.getImageData(0, 0, 30, 30);
oldBackground = newBackground;
}

function nave() {
// Dibujemos la nave usando curbas de bezier.
// Primero pintemos el fuselaje en azul
ctx.fillStyle = "rgb(0, 0, 255)";
ctx.beginPath();
ctx.moveTo(28.4, 16.9);
ctx.bezierCurveTo(28.4, 19.7, 22.9, 22.0, 16.0, 22.0);
ctx.bezierCurveTo(9.1, 22.0, 3.6, 19.7, 3.6, 16.9);
ctx.bezierCurveTo(3.6, 14.1, 9.1, 11.8, 16.0, 11.8);
ctx.bezierCurveTo(22.9, 11.8, 28.4, 14.1, 28.4, 16.9);
ctx.closePath();
ctx.fill();

// ahora la cabina en rojo
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.beginPath();
ctx.moveTo(22.3, 12.0);
ctx.bezierCurveTo(22.3, 13.3, 19.4, 14.3, 15.9, 14.3);
ctx.bezierCurveTo(12.4, 14.3, 9.6, 13.3, 9.6, 12.0);
ctx.bezierCurveTo(9.6, 10.8, 12.4, 9.7, 15.9, 9.7);
ctx.bezierCurveTo(19.4, 9.7, 22.3, 10.8, 22.3, 12.0);
ctx.closePath();
ctx.fill();

// guardamos la imagen de la nave
ship = ctx.getImageData(0, 0, 30, 30);
}

function gameLoop() {
ctx.putImageData(oldBackground, oldX, oldY);
ctx.putImageData(ship, newX, newY);
}

function moverNave (event) {
event.preventDefault(); //To prevent default behavior
oldX = newX;
oldY = newY;
oldBackground = newBackground;
ctx.putImageData(oldBackground, oldX,oldY);
var eventTouch;
eventTouch = event.changedTouches[0];
newX = eventTouch.pageX - 15;
newY = eventTouch.pageY - 60;
newBackground = ctx.getImageData(newX, newY, 30, 30);
}
</script>

Listado 6. Código completo. Disponible en https://gist.github.com/pedrogk/9352563

Conclusión

En este artículo hemos visto a grandes rasgos como crear y manipular elementos de un Canvas en HTML5. También hemos conocido elementos esenciales de cualquier videojuego, tales como registrar eventos y manipular objetos gráficos. Si quieres continuar, te dejamos como ejercicio que modifiques el código para hacer que tu nave se mueva poco a poco con una trayectoria, y puedas alterar dicha trayectoria al tocar la pantalla.

Para aprender más acerca de herramientas y tecnologías para crear aplicaciones para Android, te recomendamos visitar la Zona para desarrolladores de Intel.