Aprende a crear juegos en HTML5 Canvas

lunes, 23 de enero de 2012

Parte 2. Animando el canvas.

En la primer parte, vimos como dibujar en nuestro lienzo. Eso está bien, pero un juego se trata de interactuar con los objetos, no solo de dibujarlos. Por tanto, necesitamos por comenzar a darle movimiento a nuestro rectángulo.

Primero, declararemos dos nuevas variables: “x” y “y”. Al comienzo, tras declarar las variables canvas y ctx, agregaremos la siguiente línea:
var x = 50,
    y = 50;
Y modificaremos nuestra función “paint” para que limpie la pantalla antes de volver a dibujar en ella, esto se hace dibujando un rectángulo del tamaño completo del lienzo. Posteriormente dibujamos el rectángulo en las coordenadas mencionadas, el cual haremos de paso un poco más pequeño:
function paint(ctx) {
    ctx.fillStyle = '#000';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    ctx.fillStyle = '#0f0';
    ctx.fillRect(x, y, 10, 10);
}
En este ejemplo, estamos dibujando el rectángulo de fondo de color negro. Puedes darle cualquier valor hexadecimal desde '#000' hasta '#fff'. Experimenta con colores diferentes para que encuentres el que consideres quede mejor con tu juego.

Ahora, nuestra función “init” llama solo una vez a la función “paint”, por lo que todo es pintado solo una vez. Para que en verdad se trate de una animación, tenemos que hacer que se llame a la función una y otra vez cada determinado tiempo. Para esto, llamaremos a una función “run()”, sustituyendo donde se llamaba a “paint(ctx)” en la función “init”:
    run();
Y crearemos la función “run” de esta forma:
function run() {
    window.requestAnimationFrame(run);
    act();
    paint(ctx);
}
En la primer línea, llamaremos a un requestAnimationFrame. Esta función pedirá al navegador para el siguiente momento en que pueda realizar un cuadro de animación, usualmente a 60 cuadros por segundo en computadoras de buen rendimiento, aunque puede variar en computadoras de rendimiento menor. Para saber más al respecto, ve al Apendice 1: RequestAnimationFrame.

Posteriormente, llamamos a las funciones "act()" y "paint(ctx)". Hemos visto antes que "paint" dibuja todo en nuestro lienzo. La función "act" es usada para llamar a todas las acciones en nuestro juego; en este caso, moveremos nuestro rectángulo sumándole 2 pixeles por cuadro a nuestra variable "x":
function act(){
    x += 2;
}
Aun cuando las acciones pudieran ser puestas en la función "paint", es recomendado hacerlo por aparte, para prevenir errores, como en el que lo que se muestra en pantalla no es lo mismo que ocurre realmente (Si mezclas ambos al mismo tiempo esto puede ocurrir, por eso es mejor mover primero y al final dibujarlo). Además, hacerlo de forma separada facilita saber dónde ocurren los eventos para modificarlos posteriormente.

Guardemos y abramos de nuevo nuestra página “index.html”. Si lo hicimos bien, ¡Veremos a nuestro pequeño rectángulo correr por el lienzo! Allá va... Allá va... Y se fue...

Sí, se fue, y no volverá... Si queremos verlo de nuevo, habrá que actualizar la página, y volverá a hacer lo mismo. Pero si queremos mantener a nuestro rectángulo dentro, podemos condicionarlo a que regrese a la pantalla si sale de esta, agregando las siguientes dos líneas después de “x += 2;”:
    if (x > canvas.width) {
        x = 0;
    }
Así le indicamos que si su posición es mayor a la del ancho de lienzo, regrese a la posición 0. Si actualizamos la página ahora, veremos que nuestro rectángulo sale por una esquina, y vuelve a aparecer una y otra vez por la opuesta.

Problema de compatibilidad:


Debido a que algunas versiones antiguas de navegadores no soportan requestAnimationFrame como tal, deberías agregar esta función al final de tu código (más información en el Apéndice 1: RequestAnimationFrame):
window.requestAnimationFrame = (function () {
    return window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 17);
        };
}());

Código final:

[Canvas not supported by your browser]
var canvas = null,
    ctx = null,
    x = 50,
    y = 50;

window.requestAnimationFrame = (function () {
    return window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 17);
        };
}());

function paint(ctx) {
    ctx.fillStyle = '#000';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    ctx.fillStyle = '#0f0';
    ctx.fillRect(x, y, 10, 10);
}

function act() {
    x += 2;
    if (x > canvas.width) {
        x = 0;
    }
}

function run() {
    window.requestAnimationFrame(run);
    act();
    paint(ctx);
}

function init() {
    canvas = document.getElementById('canvas');
    ctx = canvas.getContext('2d');
    
    run();
}

window.addEventListener('load', init, false);

28 comentarios:

  1. Muy bien explicado

    Gracias por la info

    ResponderBorrar
  2. Me gusta muchisimo, con este principio se pueden desarrollar muchos juegos, solo es cuestion de añadir deteccion de coliciones , puntaje y tal vez alguna funcion aleatoria y ya está.. Super!

    ResponderBorrar
    Respuestas
    1. ¡Precisamente! Y eso es lo que se ve en las siguientes partes de este curso ;)

      Borrar
  3. Juego de poker multiplayer online, donde puedas jugar en tiempo real online con tus amigos.
    Es posible con html5?, que se necesita?, si no fuese mucha molestia desarrollar un tutorial para implementarlo.

    ResponderBorrar
    Respuestas
    1. ¡Por supuesto que es posible con HTML5! Pero desarrollar algo tan complejo como un juego multiplayer en tiempo real, llevaría varios meses para hacer el tutorial. Sin embargo, te diré lo que necesitas para desarrollarlo.

      Primero, aprende a crear el juego de poker en HTML5, sin pensar en las varias PC, puedes buscar tutoriales para esto en Internet. Después, le agregarás la función multiplayer, para eso necesitarás de Websockets, investígalos cuando termines tu juego.

      Mucha suerte :)

      Borrar
    2. Tengo una pequeña duda con respecto a la programacion sobre la funcionalidad del juego, ¿la funcionalidad va programada en javascript y se usa html5 solo para llamar al codigo javascript donde esta realmente todo el juego?, websockets se usara para la conectividad en tiempo real entre los jugadores y servidor, ademas lei por ahi que necesito node.js y socket.io ¿sabes para que sirve cada uno?, vaya que necesito leer muchisimo para poder terminar esto. En fin, el juego lo tengo echo en flash pero queria pasarlo a html5, por ahora dejare eso de lado y vere como hago para lograr el tema del multiplayer. Muchisimas gracias por tu tiempo.

      Borrar
    3. Exactamente eso es lo que se hace, tal como se muestra en este tutorial. Lo bueno es que ActionScript y JavaScript son muy similares, por lo que hacer el juego en HTML5 no será muy complicado si ya lo has hecho en Flash.

      Websockets es tecnología HTML5 lado cliente, para hacer una conexión en tiempo real, necesitas un código lado cliente (Que sería tu juego), y un código lado servidor que maneje las conexiones entre jugadores, que puede ser PHP, Python, Perl, ASP, JSP, entre muchos más. Uno de los más actuales y populares es Node.js, que implementándole el nuevo Socket.io, te permitirá crear Websockets con mucha mayor facilidad de lo que era años atrás. Puedes usar los servidores de Heroku para desarrollar tu aplicación, si aun no tienes uno.

      ¡Mucha suerte!

      Borrar
  4. Muchas gracias! Tengo muchas ganas de aprender a hacer juegos así, por navegador, para no tener que obligar al jugador a descargarse ni el juego ni los datos, pues todo se carga online. Prové un tutorial donde hacían un snake pero no iba, y el tuyo me va perfecto. ESTO debe ser un tutorial: comenzar por cosas muy sencillas pero que el usuario vea como cobran vida. Yo estoy muy avanzado en programación (C++ y Game Maker) pero en este nuevo entorno soy un principiante, veo que con tus tutoriales aprenderé mucho ^^

    ResponderBorrar
    Respuestas
    1. Precisamente yo comencé a explorar los juegos online para permitir a los usuarios jugar pronto y sin que tuvieran que descargar ni instalar nada. Me alegra que compartir mis conocimientos ayude a más gente a lograr esta meta de forma sencilla.

      Gracias por tu comentario ;)

      Borrar
  5. Notable , excelente explicacion amigo karl .

    ResponderBorrar
  6. a mi no me dejo y o se como corregir ese error, me sale la pantalla gris

    ResponderBorrar
    Respuestas
    1. Revisa la consola de JavaScript para ver si no te reporta ningún error. Al final del tema anterior, se muestra como acceder a ella.

      Borrar
  7. una cosa, igual no he leido bien...
    he estado como medio segundo que no sabia muy bien que fallaba porque dice de hacer "requestAnimationFrame(repaint);" y como no conocia bien el metodo pues no me ha parecido raro, pero como parametro hay que pasarle la funcion de callback a la que tiene que llamar (que en este caso era "run", como bien has explicado despues) y si pones eso de "repaint" no funcionara, dado que la funcion repaint no existe.
    solo por si sirve de ayuda...

    ResponderBorrar
    Respuestas
    1. Gracias por notificarme! Este fue un error de copiado, tomado del ejemplo del capítulo siguiente. Ya lo corrijo; gracias por notar el detalle.

      Borrar
  8. Muy bien explicado chabon!!! espero que sigas así explicando tan bien como lo estás haciendo, recién terminé de verme un curso de javascript lo más básico y bueno esto de la animación no sabia, y me sirve muchísimo para Unity que me hincha las bolas con los Scripts!!!!

    ResponderBorrar
  9. Excelente! es interesante ver los sustitutos de setTimeout y su corrección en navegadores antiguos, gran tutorial sigue así!

    ResponderBorrar
  10. Estos tutoriales son un paraíso.. ¡¡Muchas gracias por compartirlos con nosotros!! ^^

    ResponderBorrar
  11. Hola como podemos marcar los limites de alto y ancho para que no pase del fondo

    ResponderBorrar
    Respuestas
    1. ¿Te refieres a los del lienzo o del rectángulo?

      Los de lienzo son delimitados por canvas.width y canvas.height. Los del rectángulo se ven en la siguiente entrada, creando un objeto de tipo rectángulo que incluye estas y más propiedades.

      Borrar