Creando animaciones con canvas, javascript y HTML5.

5 de noviembre de 2016
Última actualización: 21 de agosto de 2020.

Libro electrónico gratis:<br>Miguel de Cervantes Saavedra Novelas ejemplares
Libro electrónico gratis:
Miguel de Cervantes Saavedra
Novelas ejemplares
Libro electrónico gratis:<br>Manuel Payno El fistol del diablo
Libro electrónico gratis:
Manuel Payno
El fistol del diablo
Libro electrónico gratis:<br>Homero La Odisea
Libro electrónico gratis:
Homero
La Odisea

CANVAS es una alternativa para crear animaciones interactivas y multiplataforma que funcionen en dispositivos móviles y computadoras de escritorio.

Contenido

Introducción

En el año 2010 Steve Jobs le declaró la guerra a Adobe Flash para apoderarse del mercado y los dólares de las rich internet applications. Como alternativa a Adobe Flash Steve Jobs sugirió utilizar la naciente tecnología de CANVAS o crear una app con código nativo (donde el pago de la licencia va para Apple y por cada venta Apple se lleva su comisión)

Ahora en el año 2016, ya sin soporte para Adobe Flash en los dispositivo móviles, hay varias alternativas para crear animaciones multiplataforma:

En estos 6 años han surgido animaciones y videojuegos hechos con canvas bastante interesantes. Tenemos por ejemplo:

La facilidad de uso y el poder de Adobe Flash produjeron en su tiempo un auge en el desarrollo de videojuegos. Casi cualquiera podía hacer su videojuego. Adobe Flash liberó el potencial creativo de miles de personas a lo largo del mundo.

Con CANVAS las cosas son diferentes... ni es tan fácil ni tan poderoso como Adobe Flash.

Comienzan a surgir programas que permiten animar en CANVAS, tenemos por ejemplo:

Durante varios años google ofreció swiffy, una herramienta para convertir animaciones en Flash en animaciones en CANVAS. Desafortunadamente en el año 2016 Google descontinuó el servicio y dejó a muchos usuarios huérfanos.

Para animar en CANVAS se necesita javascript. Todo se crea con javascript. Javascript es a CANVAS, lo que ActionScript era a Adobe Flash.

Crear un canvas

CANVAS utiliza un elemento nuevo de HTML5:

<canvas></canvas>

Con ayuda de los atributos width y height podemos definir el ancho y el alto de nuestro CANVAS:

<canvas width="450" height="202"></canvas>

Es conveniente asignar un atributo id a nuestro elemento canvas, con ello podremos referirnos a él y utilizarlo desde javascript:

<canvas id="canvas" width="450" height="202"></canvas>

Agregaremos un marco de color con CSS a nuestro CANVAS para distinguirlo:

<canvas id="canvas" width="450" height="202" style="border:3px solid #ccc;"></canvas>

Insisto nuevamente: para crear animaciones en canvas necesitamos javascript. En nuestro documento debemos insertar el código javascript para crear nuestra animación. En estos ejemplos estamos ya usando los ES6 modules de javascript, por lo que el código javascript debe ir después del elemento canvas y especificado el type. Ejemplo:

<canvas id="canvas" width="450" height="202" style="border:3px solid #ccc;"></canvas> <script type="module"> // aqui escribiré mi código javascript </script>

El código completo para crear un CANVAS sería:

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <canvas id="canvas" width="450" height="202" style="border:3px solid #ccc;"> Tu navegador no soporta canvas </canvas> <script type="module"> function animacion_con_canvas() // creamos la función animacion_con_canvas { const mi_canvas = document.getElementById("canvas"); // el elemento bautizado "canvas" sera usado para crear la animaciòn const contexto = mi_canvas.getContext("2d"); // creamos el objeto contexto para poder animar en canvas // contexto es un objeto. Como todo objeto tiene propiedades métodos y eventos // canvas soporta animaciones en 2d y en 3d, en este ejemplo usaremos animaciones 2d } animacion_con_canvas(); // cuando la página se cargue, ejecutaremos la función animacion_con_canvas(); </script> </body> </html>

El resultado de este ejercicio se puede ver aquí: Mi primer canvas.

¿Dónde están las explosiones? ¿Dónde está la animación? ¡Devúelvanme mi dinero! Por ahora hemos sólo hemos creado nuestro CANVAS.

Dibujar en canvas

CANVAS tienes métodos que permite dibujar líneas, parábolas, rectángulos, cuadrados, círculos, etc..

Para dibujar un círculo, un rectángulo o una línea podemos usar los métodos, propiedades y eventos del objet context.

Para dibujar un círculo el código necesario es:

contexto.strokeStyle = "black"; // contexto es un objeto. Como todo objeto tiene propiedades métodos y eventos // aqui utilizamo la propiedad strokeStyle para definir el color del contorno del objeto a dibujar // el valor asignado es un color en el formato rgb contexto.lineWidth = 5; // aqui utilizamo la propiedad lineWidth para definir el ancho del contorno del objeto a dibujar // el valor asignado es un número entero y se traduce en pixeles contexto.arc(100, 100, 20, (Math.PI/180)*0, (Math.PI/180)*360, false); // aqui utilizamo el método arc para crear un círculo // el método arc se utiliza para crear parábolas, pero con los parámetros suficientes se puede crear un círculo // el método arc utiliza las variables: // (posición en x, posición en y, radio / tamaño del círculo, ángulo incial, ángulo final, sentido del arco a dibujar) contexto.stroke(); // utiliza el metodo stroke para mostrar en el cavas nuestro círculo

El código completo para dibujar un círculo en nuestro CANVAS sería:

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <canvas id="canvas" width="450" height="202" style="border:3px solid #ccc;"> Tu navegador no soporta canvas </canvas> <script type="module"> function animacion_con_canvas() // creamos la función animacion_con_canvas { const mi_canvas = document.getElementById("canvas"); // el elemento bautizado "canvas" sera usado para crear la animaciòn const contexto = mi_canvas.getContext("2d"); // creamos el objeto contexto para poder animar en canvas // contexto es un objeto. Como todo objeto tiene propiedades métodos y eventos // canvas soporta animaciones en 2d y en 3d, en este ejemplo usaremos animaciones 2d contexto.strokeStyle = "#000000"; // contexto es un objeto. Como todo objeto tiene propiedades métodos y eventos // aqui utilizamo la propiedad strokeStyle para definir el color del contorno del objeto a dibujar // el valor es un color en formato rgb contexto.lineWidth = 5; // aqui utilizamo la propiedad lineWidth para definir el ancho del contorno del objeto a dibujar contexto.arc(100, 100, 20, (Math.PI/180)*0, (Math.PI/180)*360, false); // aqui utilizamo el método arc para crear un círculo // el método arc se utiliza para crear parábolas, pero con los parámetros suficientes se puede crear un círculo // el método arc utiliza las variables (posición en x, posición en y, radio / tamaño del círculo, ángulo incial, ángulo final, sentido del arco a dibujar) contexto.stroke(); // utiliza el metodo stroke para mostrar en el cavas nuestro círculo } animacion_con_canvas(); // cuando la página se cargue, ejecutarmos otra función animacion_con_canvas(); </script> </body> </html>

El resultado de este ejercicio se puede ver aquí: Dibujando un círculo en CANVAS.

Insertar una imagen en canvas

Se pueden insertar imágenes jpg, png o svg en nuestro CANVAS. Incluso es posible insertar vídeos en formato .mp4 u .ogg. Más aún, se puede extraer un cuadro / frame de un vídeo e insertarlo en el CANVAS.

Para insertar imágenes jpg, png o svg el código necesario es:

let img_palomita = new Image(); // creamos un objeto del tipo imagen // Como todo objeto tiene propiedades métodos y eventos img_palomita.src ="./i/canvas/01.png"; // con la propiedad src definimos la imagen a cargar. DEBE ESCRIBIRSE LA RUTA CORRECTA A LA IMAGEN img_palomita.addEventListener('load', mostrar_imagen, false); // para poder mostrar la imagen, primero debe cargarse... // la imagen tienen el evento load, que se produce cuando la imagen se ha descargado en el navegador // el método EventListener permite verificar cuando la imagen se ha cargado // cuando la imagen se ha cargado ejecutaremos la función mostrar_imagen, que mostrará la imágen en el canvas // el método EventListener utiliza las variables (evento, función a ejecutar, indica si se desea iniciar el registro del evento) function mostrar_imagen() // creamos la función mostrar_imagen para mostrar la imagen en el canvas // esta función se ejecuta cuando la imagen se ha cargado { contexto.drawImage(img_palomita, 309, 21); // aqui utilizamo el método drawimage para mostrar a nuestra imagen dentro del canvas // el método drawimage utiliza las variables (imagen a cargar, posición en x, posición en y) // el método drawimage se puede usar indistintamente para cargar imágenes jpg, png o svg }

El código completo para insertar una imagen en nuestro CANVAS sería:

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <canvas id="canvas" width="450" height="202" style="border:3px solid #ccc;"> Tu navegador no soporta canvas </canvas> <script type="module"> function animacion_con_canvas() // creamos la función animacion_con_canvas { const mi_canvas = document.getElementById("canvas"); // el elemento bautizado "canvas" sera usado para crear la animaciòn const contexto = mi_canvas.getContext("2d"); // creamos el contexto para poder animar en canvas // canvas soporta animaciones en 2d y en 3d, en este ejemplo usaremos animaciones 2d let img_palomita = new Image(); // creamos un objeto del tipo imagen // Como todo objeto tiene propiedades métodos y eventos img_palomita.src ="./i/canvas/01.png"; // con la propiedad src definimos la imagen a cargar. DEBE ESCRIBIRSE LA RUTA CORRECTA A LA IMAGEN img_palomita.addEventListener('load', mostrar_imagen, false); // para poder mostrar la imagen, primero debe cargarse... // la imagen tienen el evento load, que se produce cuando la imagen se ha descargado en el navegador // el método EventListener permite verificar cuando la imagen se ha cargado // cuando la imagen se ha cargado ejecutaremos la función mostrar_imagen, que mostrará la imágen en el canvas // el método EventListener utiliza las variables (evento, función a ejecutar, indica si se desea iniciar el registro del evento) function mostrar_imagen() // creamos la función mostrar_imagen para mostrar la imagen en el canvas // esta función se ejecuta cuando la imagen se ha cargado { contexto.drawImage(img_palomita, 309, 21); // aqui utilizamo el método drawimage para mostrar a nuestra imagen dentro del canvas // el método drawimage utiliza las variables (imagen a cargar, posición en x, posición en y) // el método drawimage se puede usar indistintamente para cargar imágenes jpg, png o svg } } animacion_con_canvas(); // cuando la página se cargue, ejecutarmos la función animacion_con_canvas(); </script> </body> </html>

El resultado de este ejercicio se puede ver aquí: Insertando una imagen en canvas

Animar en canvas

¿Y que hay de la animación? En tiempos remotos se utilizaba el método setInterval() de javascript para hacer animaciones en canvas. Se lograba animar, pero era ineficiente.

Ahora se ha creado el método requestAnimationFrame(). Paradójicamente hay navegadores que pueden trabajar con CANVAS... pero no con requestAnimationFrame(). RequestAnimationFrame() intenta ejecutar una función 60 veces por segundo... si el navegador y el dispositivo utilizado lo permite.

CANVAS crea animaciones cuadro por cuadro, frame by frame. 100 años después de la invención del cine se sigue usando el mismo método para animar. Se dibuja un cuadro. Se dibuja otro cuadro. Se dibuja otro cuadro. Y así hasta el infinito. El secreto está en mostrar sucesivamente esos cuadros para crear la ilusión de animación. El método RequestAnimationFrame() intenta mostrar 60 cuadros por segundo. ¡Más rápido que el cine!

A continuación crearemos una animación sencilla. Una imagen la desplazaremos de izquierda a derecha. Para crear esa animación podríamos utilizar este código:

img_palomita.addEventListener('load', animar_imagen, false); // para poder mostrar la imagen, primero debe cargarse... // la imagen tienen el evento load, que se produce cuando la imagen se ha descargado en el navegador // el método EventListener permite verificar cuando la imagen se ha cargado // cuando la imagen se ha cargado ejecutaremos la función animar_imagen, que animará la imágen en el canvas // el método EventListener utiliza las variables (evento, función a ejecutar, indica si se desea iniciar el registro del evento) let xpos = 0; // posicion inicial de nuesto objeto a animar const velocidad = 0.16; // cuantos pixeles en 0.016 segundos avanzara nuestro objeto a animar // IMPORTANTE: requestAnimationFrame() se ejecuta 60 veces por segundo // aqui el objeto se animará 10 pixeles por segundo // 0.16 = 10 pixeles por segundo / 60 veces por segundo que se ejecuta requestAnimationFrame() // si queremos que nuesto objeto se mueva más rápido o lento, solo tenemos que modificar la velocidad function animar_imagen() // creamos la función mostrar_imagen para mostrar la imagen en el canvas // esta función se ejecuta cuando la imagen se ha cargado { const fx_animar_imagen = requestAnimationFrame(animar_imagen); // invocamos la función requestAnimationFrame // requestAnimationFrame intenta ejecutar una función 60 veces por segundo // en este caso ejecutará la función animar_imagen // el método requestAnimationFrame utiliza las variables (función a ejecutar) contexto.fillStyle = "#ffffff"; // contexto es un objeto. Como todo objeto tiene propiedades métodos y eventos // aqui utilizamo la propiedad fillStyle para definir el color de fondo de objeto a dibujar contexto.fillRect(0, 0, 450, 202); // aqui utilizamo el método fillRect para crear un rectángulo // el método fillRect utiliza las variables (posición en x, posición en y, ancho, alto) // creamos un rectangulo para borrar el fondo // CANVAS crea animaciones cuadro por cuadro, frame by frame. // 100 años después se sigue usando el mismo método para animar. // Se dibuja un cuadro. Se dibuja otro cuadro. Se dibuja otro cuadro. Y así hasta el infinito. // El secreto está en mostrar sucesivamente esos cuadros para crear la ilusión de animación. // El método RequestAnimationFrame() intenta mostrar 60 cuadros por segundo. ¡Más rápido que el cine! // creamos un rectangulo para borrar el cuadro dibujado previamente por CANVAS contexto.drawImage(img_palomita, xpos, 21); // aqui utilizamo el método drawimage para mostrar a nuestra imagen dentro del canvas // el método drawimage utiliza las variables (imagen a cargar, posición en x, posición en y) // el método drawimage se puede usar indistintamente para cargar imágenes jpg, png o svg // aquí la posición en x cambiará dinámicamente xpos = xpos + velocidad; // aumentamos el valor de xpos con el valor de velocidad }

El código completo para insertar animar una imagen en nuestro CANVAS y animarla sería:

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <canvas id="canvas" width="450" height="202" style="border:3px solid #ccc;"> Tu navegador no soporta canvas </canvas> <script type="module"> function animacion_con_canvas() // creamos la función animacion_con_canvas { const mi_canvas = document.getElementById("canvas"); // el elemento bautizado "canvas" sera usado para crear la animaciòn const contexto = mi_canvas.getContext("2d"); // creamos el contexto para poder animar en canvas // canvas soporta animaciones en 2d y en 3d, en este ejemplo usaremos animaciones 2d let img_palomita = new Image(); // creamos un objeto del tipo imagen // Como todo objeto tiene propiedades métodos y eventos img_palomita.src ="./i/canvas/01.png"; // con la propiedad src definimos la imagen a cargar. DEBE ESCRIBIRSE LA RUTA CORRECTA A LA IMAGEN img_palomita.addEventListener('load', animar_imagen, false); // para poder mostrar la imagen, primero debe cargarse... // la imagen tienen el evento load, que se produce cuando la imagen se ha descargado en el navegador // el método EventListener permite verificar cuando la imagen se ha cargado // cuando la imagen se ha cargado ejecutaremos la función mostrar_imagen, que mostrará la imágen en el canvas // el método EventListener utiliza las variables (evento, función a ejecutar, indica si se desea iniciar el registro del evento) let xpos = 0; // posicion inicial de nuesto objeto a animar const velocidad = 0.16; // cuantos pixeles en 0.016 segundos avanzara nuestro objeto a animar // IMPORTANTE: requestAnimationFrame() se ejecuta 60 veces por segundo // aqui el objeto se animará 10 pixeles por segundo // 0.16 = 10 pixeles por segundo / 60 veces por segundo que se ejecuta requestAnimationFrame() // si queremos que nuesto objeto se mueva más rápido o lento, solo tenemos que modificar la velocidad function animar_imagen() // creamos la función animar_imagen para mostrar y mover la imagen en el canvas // esta función se ejecuta cuando la imagen se ha cargado { const fx_animar_imagen = requestAnimationFrame(animar_imagen); // invocamos la función requestAnimationFrame // requestAnimationFrame intenta ejecutar una función 60 veces por segundo // en este caso ejecutará la función animar_imagen // el método requestAnimationFrame utiliza las variables (función a ejecutar) contexto.fillStyle = "#ffffff"; // contexto es un objeto. Como todo objeto tiene propiedades métodos y eventos // aqui utilizamo la propiedad fillStyle para definir el color de fondo de objeto a dibujar contexto.fillRect(0, 0, 450, 202); // aqui utilizamo el método fillRect para crear un rectángulo // el método fillRect utiliza las variables (posición en x, posición en y, ancho, alto) // creamos un rectangulo para borrar el fondo // CANVAS crea animaciones cuadro por cuadro, frame by frame. // 100 años después se sigue usando el mismo método para animar. // Se dibuja un cuadro. Se dibuja otro cuadro. Se dibuja otro cuadro. Y así hasta el infinito. // El secreto está en mostrar sucesivamente esos cuadros para crear la ilusión de animación. // El método RequestAnimationFrame() intenta mostrar 60 cuadros por segundo. ¡Más rápido que el cine! // creamos un rectangulo para borrar el cuadro dibujado previamente por CANVAS contexto.drawImage(img_palomita, xpos, 21); // aqui utilizamo el método drawimage para mostrar a nuestra imagen dentro del canvas // el método drawimage utiliza las variables (imagen a cargar, posición en x, posición en y) // el método drawimage se puede usar indistintamente para cargar imágenes jpg, png o svg // aquí la posición en x cambiará dinámicamente xpos = xpos + velocidad; // aumentamos el valor de xpos con el valor de velocidad } animar_imagen(); // ejecutamos la funcion animar_imagen() que creará un loop eterno // el loop ejecutara la funcion animar_imagen() // animar_imagen() irá dibujando cuadro por cuadro nuestra animaciòn } animacion_con_canvas(); // cuando la página se cargue, ejecutaremos la función animacion_con_canvas(); </script> </body> </html>

El resultado de este ejercicio se puede ver aquí: animar una imagen en CANVAS.

Para los curiosos: ¿Que pasaría si no borramos el cuadro previamente dibujado por CANVAS? El resultado de este ejercicio se puede ver aquí: animar una imagen en CANVAS sin borrar el cuadro previo.

Animaciones sucesivas e interactivas en canvas

Con CANVAS se pueden crear animaciones sucesivas, interactivas y que simulen escenas como en Adobe Flash. El resultado de este ejercicio se puede ver aquí: Animación sucesiva e interactivas en canvas

El código fuente de esta animación es:

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Animaciones Sucesivas</title> </head> <body> <canvas id="canvas" width="450" height="202" style="cursor:pointer; border:3px solid #ccc; cursor:pointer;"> Tu navegador no soporta canvas </canvas> <script type="module"> function animacion_con_canvas() { const mi_canvas = document.getElementById("canvas"); // el elemento bautizado "canvas" sera usado para crear la animaciòn const contexto = mi_canvas.getContext("2d"); // creamos el contexto para poder animar en canvas // canvas soporta animaciones en 2d y en 3d, en este ejemplo usaremos animaciones 2d // creamos varios objetos del tipo imagen let img_fondo = new Image(); let img_palomita = new Image(); let img_encuesta = new Image(); let img_clima = new Image(); let img_fecha = new Image(); let img_participa = new Image(); // con la propiedad src definimos la imagen a cargar. DEBE ESCRIBIRSE LA RUTA CORRECTA A LA IMAGEN img_fondo.src ="./i/canvas/00.png"; img_palomita.src ="./i/canvas/01.png"; img_encuesta.src ="./i/canvas/02.png"; img_clima.src ="./i/canvas/03.png"; img_fecha.src ="./i/canvas/04.png"; img_participa.src ="./i/canvas/05.png"; let intro_alpha =0; // el alpha / transparencia original será 0, completamente transparente let alpha_velocidad = 0.0055555556; // velocidad para aparecer // requestAnimationFrame muestra 60 frames por segundo // 60 frames = 1 segundo // 600 frames = 10 segundos // 1 (alpha full) / 180 (frames _ 3 segundos) = 0.0055555556 let pausa_en_stage = 5000; // velocidad para mostrarse en pantalla una imagen estática let timeout_imagen_estatica; // creamos una variable que reiniciara las cuentas regresivas img_participa.addEventListener('load', iniciar_animacion, false); // valida que la imagen se haya cargado // ejecuta la función iniciar_animacion function iniciar_animacion() { intro_in(); // ejecuta la funcion intro_in } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // muestra fondo, una imagen se mostrará siempre como fondo // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function muestra_fondo() { contexto.fillStyle = "#ffffff"; // borra el fondo contexto.fillRect(0, 0, 450, 202); // crea un rectangulo para borrar el fondo contexto.drawImage(img_fondo, 0, 0); contexto.drawImage(img_palomita, 309, 21); } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // creamos la primera escena // simplemente muestra una transición de una imagen de alpha 0 a 1 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function intro_in() { const intro_in_fx = requestAnimationFrame(intro_in); // invocamos la función requestAnimationFrame // requestAnimationFrame intenta ejecutar una función 60 veces por segundo // en este caso ejecutará la función intro_in // el método requestAnimationFrame utiliza las variables (función a ejecutar) muestra_fondo(); // mostramos la imagen que siempre usaremos de fondo contexto.save(); // guarda el canvas como esta, con el fondo en pantalla // "crearemos" un segundo canvas al que aplicaremos cambios contexto.globalAlpha = intro_alpha; // le aplicamos un alpha a nuestro canvas, al inicio será 0 // el alpha se incrementará gradualmente contexto.drawImage(img_encuesta, 15, 63); // en nuestro canvas con un alpha modificado mostramos una imagen contexto.drawImage(img_clima, -1, 102); // en nuestro canvas con un alpha modificado mostramos otra imagen intro_alpha = intro_alpha + alpha_velocidad; // aumentamos el alpha para el siguiente frame contexto.restore(); // despues de hacer los cambios // restauramos y mezclamos el canvas guardado // el resultado es que combinamos dos canvas: uno con alpha 0 y otro con alpha 1 if(intro_alpha > 1) // si la imagen es completamente visible { intro_alpha = 0; // restauramos el alpha original, pues crearemos un loop infinito window.cancelAnimationFrame(intro_in_fx); // elimina el requestanimationframe que creo la primnera escena / transición intro_estatica(); // muestra las cosas sin movimiento... } } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // creamos la primera escena // simplemente muestra tres imagen fijas con un alpha 1, completamente visible // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function intro_estatica() { muestra_fondo(); // mostramos la imagen que siempre usaremos de fondo contexto.drawImage(img_encuesta, 15, 63); // mostramos la segunda imagen con un alpha = 1 contexto.drawImage(img_clima, -1, 102); // mostramos la tercera imagen con un alpha = 1 timeout_imagen_estatica = window.setTimeout(kill_timeout_intro_estatica, pausa_en_stage); // creamos una cuenta regresiva // en 5 segundos se ejecutara kill_timeout_intro_estatica() // setTimeout(función a ejecutarse, en cuanto tiempo) } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // una vez que pasaron 5 segundos, eliminamos la cuenta regresiva // iniciamos la siguiente escena // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function kill_timeout_intro_estatica() { window.clearTimeout(timeout_imagen_estatica); // destruye la cuenta regresiva fecha_in(); // ejecuta la función fecha_in() // para iniciar la siguiente escena } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // creamos la tercera escena // simplemente muestra una transición de una imagen de alpha 0 a 1 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function fecha_in() { const fx_fecha_in = requestAnimationFrame(fecha_in); muestra_fondo(); // mostramos la imagen que siempre usaremos de fondo contexto.save(); // guarda el canvas como esta, con el fondo en pantalla // "crearemos" un segundo canvas al que aplicaremos cambios contexto.globalAlpha = intro_alpha; // le aplicamos un alpha a nuestro canvas, al inicio será 0 // el alpha se incrementará gradualmente contexto.drawImage(img_fecha, 21, 44); intro_alpha = intro_alpha + alpha_velocidad; // en nuestro canvas con un alpha modificado mostramos una imagen contexto.restore(); // despues de hacer los cambios // restauramos y mezclamos el canvas guardado // el resultado es que combinamos dos canvas: uno con alpha 0 y otro con alpha 1 if(intro_alpha > 1) // si la imagen es completamente visible { intro_alpha = 0; // restauramos el alpha original, pues crearemos un loop infinito window.cancelAnimationFrame(fx_fecha_in); // elimina el requestanimationframe que creo la tercera escena / transición fecha_estatica(); // muestra las cosas sin movimiento... } } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // intro fecha estática // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function fecha_estatica() { muestra_fondo(); // mostramos la imagen que siempre usaremos de fondo contexto.drawImage(img_fecha, 21, 44); // mostramos la segunda imagen con un alpha = 1 timeout_imagen_estatica = window.setTimeout(kill_fecha_estatica, pausa_en_stage); // creamos una cuenta regresiva // en 5 segundos se ejecutara kill_fecha_estatica() // setTimeout(función a ejecutarse, en cuanto tiempo) } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // una vez que pasaron 5 segundos, eliminamos la cuenta regresiva // iniciamos la siguiente escena // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function kill_fecha_estatica() { window.clearTimeout(timeout_imagen_estatica); // destruye la cuenta regresiva participa_in(); // ejecuta la función participa_in() // para iniciar la siguiente escena } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // creamos la quinta escena // simplemente muestra una transición de una imagen de alpha 0 a 1 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function participa_in() { const fx_participa_in = requestAnimationFrame(participa_in); // invocamos la función requestAnimationFrame // requestAnimationFrame intenta ejecutar una función 60 veces por segundo // en este caso ejecutará la función participa_in // el método requestAnimationFrame utiliza las variables (función a ejecutar) muestra_fondo(); // mostramos la imagen que siempre usaremos de fondo contexto.save(); // guarda el canvas como esta // "crearemos" un segundo canvas al que aplicaremos cambios contexto.globalAlpha = intro_alpha; // le aplicamos un alpha a nuestro canvas, al inicio será 0 // el alpha se incrementará gradualmente contexto.drawImage(img_participa, 10, 74); // en nuestro canvas con un alpha modificado mostramos una imagen intro_alpha = intro_alpha + alpha_velocidad; // aumentamos el alpha para el siguiente frame contexto.restore(); // despues de hacer los cambios // restauramos y mezclamos el canvas guardado // el resultado es que combinamos dos canvas: uno con alpha 0 y otro con alpha 1 if(intro_alpha > 1) // si la imagen es completamente visible { intro_alpha = 0; // restauramos el alpha original, pues crearemos un loop infinito window.cancelAnimationFrame(fx_participa_in); // elimina el requestanimationframe que creo la primnera escena / transición participa_estatica(); // muestra las cosas sin movimiento... } } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // creamos la sexta escena // simplemente muestra una imagen fija // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function participa_estatica() { muestra_fondo(); // mostramos el fondo contexto.drawImage(img_participa, 10, 74); // mostramos la imagen con un alpha = 1 timeout_imagen_estatica = window.setTimeout(kill_participa_estatica, pausa_en_stage); // creamos una cuenta regresiva // en 5 segundos se ejecutara kill_fecha_estatica() // setTimeout(función a ejecutarse, en cuanto tiempo) } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // una vez que pasaron 5 segundos, eliminamos la cuenta regresiva // iniciamos la siguiente escena // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function kill_participa_estatica() { window.clearTimeout(timeout_imagen_estatica); // destruye la cuenta regresiva intro_in(); // ejecuta la función intro_in() // para iniciar la siguiente escena // en los hechos se repite la primera escena para crear un loop infinito } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // cuando la gente haga click en el canvas, visitaremos una página // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function al_hacer_click(e) { window.location.href = 'http://www.alaingarcia.net/'; } mi_canvas.addEventListener("click", al_hacer_click, false); // crea un evento click para el canvas // cuando la gente haga click // ejecutaremos la función al_hacer_click() } animacion_con_canvas(); // una vez que se ha cargado la página, iniciamos la animación </script> </body> </html>

Crear objetos con propiedades, métodos y eventos y animarlos en canvas

Javascript nos permite crear objetos con sus propiedades, métodos y eventos. Esos objetos posteriormente los podemos mostrar y animar en CANVAS. El resultado de este ejercicio se puede ver aquí: Crear objetos con propiedades, métodos y eventos y animarlos en canvas

El código fuente de esta animación es:

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Crear objetos y animarlos en Canvas</title> </head> <body> <canvas id="canvas" width="750" height="300" style="border:3px solid #ccc;"> Tu navegador no soporta canvas </canvas> <script type="module"> function animacion_con_canvas() // creamos la función animacion_con_canvas { const mi_canvas = document.getElementById("canvas"); // el elemento bautizado "canvas" sera usado para crear la animaciòn const contexto = mi_canvas.getContext("2d"); // creamos el contexto para poder animar en canvas // canvas soporta animaciones en 2d y en 3d, en este ejemplo usaremos animaciones 2d let array_para_bolitas = []; // se crearan varios objetos con difefente velocidad, posición en x y posición en y // la información de cada objeto se almacenará en un array let img_bolita_roja = new Image(); // creamos un objeto del tipo imagen // Como todo objeto tiene propiedades métodos y eventos img_bolita_roja.src = "./i/canvas/k.png"; // con la propiedad src definimos la imagen a cargar. DEBE ESCRIBIRSE LA RUTA CORRECTA A LA IMAGEN img_bolita_roja.addEventListener('load', iniciar_animacion, false); // para poder mostrar la imagen, primero debe cargarse... // la imagen tienen el evento load, que se produce cuando la imagen se ha descargado en el navegador // el método EventListener permite verificar cuando la imagen se ha cargado // cuando la imagen se ha cargado ejecutaremos la función mostrar_imagen, que mostrará la imágen en el canvas // el método EventListener utiliza las variables: // (evento, función a ejecutar, indica si se desea iniciar el registro del evento) // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // función para crear objetos // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function crea_bolita(velocidad, x_pos, y_pos) // función para crear objetos // cada objeto puede tener propiedades, métodos y eventos { this.velocidad = velocidad; // cada objeto tendra una velocidad única this.x_pos = x_pos; // cada objeto tendra una posición en x única this.y_pos = y_pos; // cada objeto tendra una posición en y única } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // crea un método para el objeto // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * crea_bolita.prototype.mover_bolita = function() // crea un método para la clase / objeto // este método moverá los objetos a lo largo del plano de x { if(this.x_pos<750) // si la posición del objeto es menor a 750 { this.x_pos = this.x_pos + this.velocidad; // mueve el objeto en el plano de x acorde a su velocidad } else // si la posición del objeto es mayor a 750 { this.x_pos = 0; // mueve el objeto a la posición 0 en el plano de x this.y_pos = Math.round(Math.random() * 300); // mueve el objeto en el plano de y a una posición única } contexto.drawImage(img_bolita_roja, this.x_pos, this.y_pos); // aqui utilizamo el método drawimage para mostrar a nuestra imagen dentro del canvas // el método drawimage utiliza las variables (imagen a cargar, posición en x, posición en y) // el método drawimage se puede usar indistintamente para cargar imágenes jpg, png o svg // aquí la posición en x cambiará dinámicamente // aquí la posición en y cambiará dinámicamente }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // funcion para crear varios objetos a partir de nuestra clase // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function crear_varias_bolitas() { for (let i = 0; i < 10; i++) // con un loop crearemos varios objetos { let x_posicion_al_azar = Math.round(Math.random() * 750); // cada objeto tendrá una posición en x al azar let y_posicion_al_azar = Math.round(Math.random() * 300); // cada objeto tendrá una posición en y al azar let velocidad_al_azar = 0.2 + Math.random() * 3; // cada objeto tendrá una velocidad al azar let bolita_creada = new crea_bolita(velocidad_al_azar, x_posicion_al_azar, y_posicion_al_azar); // se crea un nuevo objeto array_para_bolitas.push(bolita_creada); // almacenamos la información del objeto creado en un array } animar_bolitas(); // tras crear los objetos, comenzamos a animarlos con la función animar_bolitas() } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // funcion para iniciar la animación // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function iniciar_animacion() { crear_varias_bolitas(); // ejecutamos la función crear_varias_bolitas() // con esa función creamos varios objetos } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // creamos una función para animar los objetos // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * function animar_bolitas() { contexto.fillStyle = "#ffffff"; // contexto es un objeto. Como todo objeto tiene propiedades métodos y eventos // aqui utilizamo la propiedad fillStyle para definir el color de fondo de objeto a dibujar contexto.fillRect(0, 0, 750, 300); // aqui utilizamo el método fillRect para crear un rectángulo // el método fillRect utiliza las variables (posición en x, posición en y, ancho, alto) // creamos un rectangulo para borrar el fondo // CANVAS crea animaciones cuadro por cuadro, frame by frame. // 100 años después se sigue usando el mismo método para animar. // Se dibuja un cuadro. Se dibuja otro cuadro. Se dibuja otro cuadro. Y así hasta el infinito. // El secreto está en mostrar sucesivamente esos cuadros para crear la ilusión de animación. // El método RequestAnimationFrame() intenta mostrar 60 cuadros por segundo. ¡Más rápido que el cine! // creamos un rectangulo para borrar el cuadro dibujado previamente por CANVAS for (let i = 0; i < array_para_bolitas.length; i++) // para cada una de los objetos creados... { let bolita_a_animar = array_para_bolitas[i]; // elegimos el objeto a animar desde nuestro array con objetos bolita_a_animar.mover_bolita(); // movemos el objeto con el método mover } const fx_animar_bolitas = requestAnimationFrame(animar_bolitas); // invocamos la función requestAnimationFrame // requestAnimationFrame intenta ejecutar una función 60 veces por segundo // en este caso ejecutará la función animar_bolitas // el método requestAnimationFrame utiliza las variables (función a ejecutar) } } animacion_con_canvas(); // cuando la página se cargue, ejecutarmos la función animacion_con_canvas(); </script> </body> </html>

Usando en canvas animaciones de celda (cell animation)

Se pueden combinar animaciones cuadro por cuadro ( frame by frame ) hechas con canvas con animaciones cuadro por cuadro ( frame by frame ) hechas con la técnica de animaciones de celda (cell animation)

100 años después de la invención del cine se sigue usando el mismo método para animar: se dibuja un cuadro, se dibuja otro cuadro, se dibuja otro cuadro... Y así hasta el infinito. El secreto está en mostrar sucesivamente esos cuadros para crear la ilusión de animación.

La técnica de animaciones de celda (cell animation) sigue el mismo principio: : se dibuja un cuadro, se dibuja otro cuadro, se dibuja otro cuadro... Y así hasta el infinito. El secreto está en mostrar sucesivamente esos cuadros para crear la ilusión de animación.

Esas animaciones cuadro por cuadro se pueden guardar en una imagen en formato jpg, png o svg. Con ayuda de sofware libre como Inkscape o Gimp podemos crear imagenes de mapas de bits (bitmaps) o imagenes svg con animaciones de celda. Entre cuadro y cuadro (frame y frame) nuestro objeto o sujeto a animar debe tener algun cambio para poder generar la ilusión de movimiento.

El resultado sería una tira (sprite: bitmap bidimensional) como esta:

El sprite debe verse como una secuencia de imagenes, que se puede dividir cuadro por cuadro / frame by frame.

Este sprite tiene 12 cuadros de 100 pixeles de ancho por 100 pixeles de alto:

Esa tira (sprite) podemos animarla usando canvas y javascript. El resultado de este ejercicio se puede ver aquí: Sprite animado en canvas

El código fuente de esta animación es:

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Crear objetos y animarlos en Canvas</title> <script type="module"> function animacion_con_canvas() // creamos la función animacion_con_canvas { const mi_canvas = document.getElementById("canvas"); // el elemento bautizado "canvas" sera usado para crear la animaciòn const contexto = mi_canvas.getContext("2d"); // creamos el contexto para poder animar en canvas // canvas soporta animaciones en 2d y en 3d, en este ejemplo usaremos animaciones 2d let img_sprite = new Image(); // creamos un objeto del tipo imagen // Como todo objeto tiene propiedades métodos y eventos img_sprite.src ="./i/canvas/epn_sprite.png"; // con la propiedad src definimos la imagen a cargar. DEBE ESCRIBIRSE LA RUTA CORRECTA A LA IMAGEN // en este caso cargamos el sprite con la animación cuadro por cuadro img_sprite.addEventListener('load', mostrar_imagen, false); // para poder mostrar la imagen, primero debe cargarse... // la imagen tienen el evento load, que se produce cuando la imagen se ha descargado en el navegador // el método EventListener permite verificar cuando la imagen se ha cargado // cuando la imagen se ha cargado ejecutaremos la función mostrar_imagen, que mostrará la imágen en el canvas // el método EventListener utiliza las variables (evento, función a ejecutar, indica si se desea iniciar el registro del evento) let cuadro_del_sprite = 0; // esta variable la usaremos para registrar que cuadro del sprite estamos usando // el sprite tiene una secuencia de imagenes que darán la ilusión de movimiento // el sprite puede dividirse en cuadros / frames // el sprite lo dividimos de izquierda a derecha. el primer cuadro se localizará del lado izquierdo // el último cuadro estará en el extremo derecho del sprite // cada cuadro / frame indica una parte de la secuencia de imagenes que darán la ilusión de movimiento // iniciaremos la animación con el primer cuadro / frame let cuadros_por_segundo = 0; // esta variable la usaremos para determinar cuantos cuadros / frames del sprite mostaremos por segundo let xpos = 0; // posicion inicial de nuesto objeto a animar dentro del canvas // ademas de animar el sprite, animaremos el sprite dentro del canvas let velocidad = 0.16; // ademas de animar el sprite, animaremos el sprite dentro del canvas // cuantos pixeles en 0.016 segundos avanzara nuestro objeto a animar // IMPORTANTE: requestAnimationFrame() se ejecuta 60 veces por segundo // aqui el objeto se animará 10 pixeles por segundo // 0.16 = 10 pixeles por segundo / 60 veces por segundo que se ejecuta requestAnimationFrame() // si queremos que nuesto objeto se mueva más rápido o lento, solo tenemos que modificar la velocidad function mostrar_imagen() // creamos la función mostrar_imagen para mostrar la imagen en el canvas // esta función se ejecuta cuando la imagen se ha cargado { const fx_animar_imagen = requestAnimationFrame(mostrar_imagen); // invocamos la función requestAnimationFrame // requestAnimationFrame intenta ejecutar una función 60 veces por segundo // en este caso ejecutará la función animar_imagen // el método requestAnimationFrame utiliza las variables (función a ejecutar) contexto.fillStyle = "#ffffff"; // contexto es un objeto. Como todo objeto tiene propiedades métodos y eventos // aqui utilizamo la propiedad fillStyle para definir el color de fondo de objeto a dibujar contexto.fillRect(0, 0, 1000, 300); // aqui utilizamo el método fillRect para crear un rectángulo // el método fillRect utiliza las variables (posición en x, posición en y, ancho, alto) // creamos un rectangulo para borrar el fondo // CANVAS crea animaciones cuadro por cuadro, frame by frame. // 100 años después se sigue usando el mismo método para animar. // Se dibuja un cuadro. Se dibuja otro cuadro. Se dibuja otro cuadro. Y así hasta el infinito. // El secreto está en mostrar sucesivamente esos cuadros para crear la ilusión de animación. // El método RequestAnimationFrame() intenta mostrar 60 cuadros por segundo. ¡Más rápido que el cine! // creamos un rectangulo para borrar el cuadro dibujado previamente por CANVAS contexto.drawImage(img_sprite, 100*cuadro_del_sprite, 0,100,100,xpos,0,100,100); // esta linea de código hace la magia de animar el sprite // aqui utilizamo el método drawimage para mostrar a nuestra imagen dentro del canvas // con los parametros adecuados podemos mostrar solo una parte del sprite // con los parámetros adecuados podemos mostrar un cuadro / frame de nuestro sprite // el método drawimage utiliza las variables: //a) imagen a cargar: img_sprite //b) posición en x dentro del sprite: 100*cuadro_del_sprite // (cada cuadro /frame tiene un ancho de 100 pixeles) // cuadro_del_sprite es una variable que almacena que cuadro /frame de nuestro sprite estamos usando //c) posición en y dentro del sprite: 0 //(nuestro sprite solo tiene una fila de cuadros / frames) //d) tamaño en x dentro del sprite: 100 //(el sprite lo podemos recortar, aque definimos el tamaño del recorte: 100 pixeles de ancho) //e) tamaño en y dentro del sprite: 100 // (el sprite lo podemos recortar, aque definimos el tamaño del recorte: 100 pixeles de alto) //f) posición en x dentro del canvas: xpos // adicionalmente animaremos el sprite dentro del canvas, // xpos almacena dinámicamente la posición en x dentro del canvas //g) posición en y dentro del canvas: 0 // la posicion en y de nuestro sprite dentro del canvas //h) tamaño en x dentro del canvas: 100 (en el canvas el sprite tendrá un tamaño de 100 pixeles de ancho) //i) tamaño en y dentro del canvas: 100 (en el canvas el sprite tendrá un tamaño de 100 pixeles de alto) // el método drawimage se puede usar indistintamente para cargar imágenes jpg, png o svg xpos = xpos + velocidad; // aumentamos el valor de xpos con el valor de velocidad cuadros_por_segundo++; // esta variable la usaremos para determinar cuantos cuadros / frames del sprite mostaremos por segundo // cada que se ejecute requestAnimationFrame aumentará en 1 el valor de cuadros_por_segundo if(cuadros_por_segundo%3==0) // en este ejemplo nuestro sprite sólo tiene 12 cuadros / frames // requestAnimationFrame intenta ejecutar una función 60 veces por segundo // debemos reducir la velocidad de la animación frame by fram / cuadro por cuadro de nuestro sprite // cuadros_por_segundo la usaremos para determinar cuantos cuadros / frames del sprite mostaremos por segundo // si cuadro cuadros_por_segundo es múltiplo de 3, mostraremos un cuadro / frame diferente del sprite // en un segundo mostraremos 20 cuadros / frames de nuestro sprite // sin esta línea de código en un segundo mostraríamos 60 cuadros / frames de nuestro sprite... { cuadro_del_sprite++; // esta variable la usaremos para registrar que cuadro / frame del sprite estamos usando // si cuadro cuadros_por_segundo es múltiplo de 3, mostraremos un cuadro / frame diferente del sprite if (cuadro_del_sprite >11) // este sprite tiene 12 cuadros / frames // cuando llegue al último frame / cuadro // comenzaremos a mostrar nuevamente el primer frame { cuadro_del_sprite = 0; // reniniciamos el sprite // mostramos el primer cuadro / frame del sprite } } } } animacion_con_canvas(); // cuando la página se cargue, ejecutarmos la función animacion_con_canvas(); </script> </head> <body> <canvas id="canvas" width="1000" height="300" style="border:3px solid #ccc;"> Tu navegador no soporta canvas </canvas> </body> </html>

Sitios de interés

Mozilla Developer Network Sitio para aprender html5, javascript, css

W3Schools Sitio para aprender html5, javascript, css, php, sql

CodeAcademy Sitio para aprender html5, javascript, css, php, sql

BrowserQuest

Asteroids

El juego de google para el Halloween de 2016

Keepout

Hexgl

Contre Jour


Comenta y opina este texto     Lee mi libro de visitas
© 1997-2024 Alain García
albegago@hotmail.com
Twitter: Youtube @feesgo
YouTube Youtube
El vínculo a este documento es:

Compartir en facebook Compartir en twitter Compartir en whatsapp Rss

Puedes apoyar a este sitio invitándome a comer...

Este sitio utiliza cookies propias y de terceros para mejorar sus servicios. Si continua navegando, entendemos que acepta su uso. Política de Privacidad