Para continuar con esta serie de tutoriales sobre HTML5 Canvas, vamos a intentar recrear un protector de pantalla clásico de Windows, llamado “mystify your mind”. En el siguiente video podemos ver un ejemplo del mismo:
Aunque vamos a tratar de darle un toque mas moderno :).
Para comenzar, partimos desde la misma base que el tutorial anterior. Un canvas vacío, de color negro, y por el lado de javascript, la inicialización del canvas y un “loop” utilizando requestAnimationFrame.
Analizando un poco el comportamiento del protector de pantallas original, podemos “reducirlo” a una serie de polígonos, con las siguientes características:
- cambian de color con el tiempo
- dejan una “estela” al moverse
- los vértices de los poligonos se mueven en linea recta
- al llegar al borde de la pantalla, los vértices cambian de dirección como si “rebotaran”
El primer paso que vamos a realizar es generar un polígono y dibujarlo en el canvas. Para poder hacer esto vamos a utilizar un conjunto de métodos y propiedades del contexto de canvas relacionadas al dibujado de “paths”. Las mismas son:
context.beginPath(); //marca el comienzo de nuestro poligono context.moveTo(x, y); //mueve la posicion de dibujado, pero sin dibujar context.lineTo(x, y); //mueve la posicion de dibujado, dibujando context.closePath(); // une el ultimo punto con el primero context.strokeStyle; //una propiedad que contiene el color que queremos usar para dibujar context.stroke(); //realiza el dibujado del path creado con las funciones anteriores
Como vemos, dibujar un polígono es un poco mas complicado que dibujar un cuadrado, simplemente por el hecho de que hay que definir al polígono antes de poder dibujarlo. Para poder entenderlo un poco mejor, vamos a ver un ejemplo, dibujando un polígono definido arbitrariamente:
Como vemos, dibujar un polígono en javascript no es mucho mas complicado que dibujar una serie de puntos. Asimismo, animar al polígono tampoco sera muy complejo. Al igual que cuando animamos los puntos para el “campo de estrellas”, tendremos que guardar la posición de los vértices en un array, y “moverlos” entre frame y frame.
Una diferencia importante a tener en cuenta es que no podemos inferir la dirección del movimiento con solo saber la posición del vértice, por lo cual vamos a tener que guardarla en el mismo array que guardamos las posiciones, y generarla al azar al momento de inicializar el array.
hay varias formas de guardar este dato, podríamos guardar un angulo en grados, o radianes, yo en este caso elegí guardarlo separado en dos componentes, x e y, porque me pareció mas simple para que todos los vértices se muevan a la misma velocidad.
Para generar este dato, usamos el siguiente código:
dir = Math.random() * Math.PI * 2; // el angulo, en radianes, es un numero entre 0 y 2*pi tomado al azar (entre 0º y 360º) dirx = Math.sin(dir); diry = Math.cos(dir); // usamos las funciones seno y coseno para separar las componentes del angulo
usando este método, el código para inicializar el array con los vértices nos quedaría así:
var vertices = []; var i; for (i = 0; i < 7; i++) { var dir = Math.random() * Math.PI * 2; vertices.push({ "x": Math.random() * canvas.width, "y": Math.random() * canvas.height, "dirx": Math.sin(dir), "diry": Math.cos(dir) }); }
Y si le sumamos el código que dibuja el polígono del array, simplemente cambiando las llamadas sucesivas a lineTo por un for que recorra el array, obtenemos lo siguiente:
Con esto, logramos dibujar un polígono al azar cada vez que recargamos el ejemplo.
Ahora, para animar el movimiento, solo tenemos que mover los vértices entra cada cuadro, utilizando el vector de velocidad que habíamos generado al comienzo, y sin olvidarnos de chequear si los vértices se “escapan” del canvas.
for(i=0 ; i<vertices.length;i++){ vertices[i].x = vertices[i].x + vertices[i].dirx * 4; vertices[i].y = vertices[i].y + vertices[i].diry * 4; if(vertices[i].x < 0 || vertices[i].x > canvas.width){ vertices[i].dirx = - vertices[i].dirx; } if(vertices[i].y < 0 || vertices[i].y > canvas.height){ vertices[i].diry = - vertices[i].diry; } }
Acá vemos que lo que hacemos para chequear esta condición es ver si el desplazamiento en x o en y del vértice lo llevaría fuera del canvas (si fuera menor que cero, o mayor que el ancho o el alto respectivamente) y en caso de ser cierto, invertimos la dirección de movimiento en ese componente, logrando así que el vértice rebote contra los bordes de la pantalla.
También agregamos una llamada a la función clearRect del contexto, para que nuestra animación se realice desde 0 en cada cuadro. Con estos cambios logramos el siguiente efecto:
Ya el protector de pantalla esta bastante avanzado, y el efecto que logramos es muy similar al original… lo que podemos hacer para finalizar el efecto es agregar la “estela” que se genera con el movimiento. Para hacerlo, podemos usar un pequeño truco… en vez de limpiar la pantalla al 100% cada vez que dibujamos, podemos dibujar un cuadrado que ocupe toda la pantalla, pero con un 10% de opacidad… con esto logramos que cada cuadro que dibujamos se mantenga en la pantalla por 10 cuadros, cada vez con menos intensidad.
Para hacer esto, solo llamamos a drawRect, habiendo establecido el fillStyle en rgba(0,0,0,.1), y obtenemos el siguiente resultado:
Ya estamos mucho mas cerca del original! Lo único que nos faltaría es poder manejar el color del polígono, pero esto lo vamos a aprovechar para explicar un poco las distintas formas de manejar colores, así que lo dejamos para una próxima edición.
Espero que les haya sido útil, y hasta el próximo tutorial!