Copos de nieve
Crear copos de nieve que caen constantemente es algo muy fácil.
En el HTML tenemos un elemento canvas, el lienzo donde queremos animar los copos de nieve.
<canvas></canvas>
En el JavaScript primero iniciamos el canvas:
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width = window.innerWidth;
var ch = canvas.height = window.innerHeight;
Las variables cw
y ch
representan, como es fácil de ver, la anchura y respectivamente la altura del canvas. Utilizamos window.innerWidth
y window.innerHeight
porque queremos que el canvas cubra toda la ventana.
Algunas variables útiles
A continuación queremos animar 300 copitos de nieve que caen lentamente del cielo.
var numCopos = 300;
El color de los copos es blanco
ctx.fillStyle = "white";
Cuando trabajamos con partículas (en este caso copitos de nieve) en canvas es importante crear un array donde guardar todas las características de cada partícula en parte.
var coposRy = [];
El constructor
En el JavaScript creamos una función Copo()
que construye una a una las partículas. En este caso las partículas son pequeños círculos cuyo radio r
, varia entre 1px y 3px.
~~(Math.random()*3 + 1);
Para quien no lo sepa, en JavaScript, la doble tilde (~~
) es un operador equivalente a Math.floor()
o casi.
Mientras que el valor de la coordenada en x
de cada partícula las sitúa repartidas aleatoriamente a lo ancho del canvas
~~(Math.random()*cw + 1);
el valor de la coordenada en y de cada partícula en el momento de la creación las sitúa fuera del canvas, justo encima de este.
this.y = -this.r;
La función Copo()
también establece la velocidad inicial de cada partícula:
this.vy , la caída, es un número integro aleatorio, entre 1 y 3.
this.vy = ~~(Math.random()*3 + 1);
Queremos que la velocidad en x tome valores entre .5 y 1.5
this.vx = ~~(Math.random() * (15 - 5 + 1) + 5)/10;
Pero esto generaría un movimiento de las partículas solo hacia la derecha. Para que esto no pase lo multiplicamos aleatoriamente con 1 o -1:
~~(Math.random() * (15 - 5 + 1) + 5)/10 * (Math.random() < .5 ? 1 : -1);
function Copo() {
this.r = ~~(Math.random()*3 + 1);// el radio
this.x = ~~(Math.random()*cw + 1);
this.y = -this.r;
this.vx = ~~(Math.random() * (15 - 5 + 1) + 5)/10 * (Math.random() < .5 ? 1 : -1);
this.vx =~~(Math.random()*3 + 1);
}
Dibujar
Para poder dibujar fácilmente cada copito, extendemos la funcionalidad del constructor de esta manera: (el código es auto explicativo).
Copo.prototype.dibujar = function(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
ctx.fill();
}
El movimiento
Si los copos se salen del canvas,
if (this.x >= cw + this.r || this.x <= -this.r || this.y >= ch + this.r )
los podemos reutilizar, colocándolos de nuevo en el punto de partida.
this.y = -this.r; this.x = ~~(Math.random()*cw + 1);
De lo contrario, sumamos al valor de las coordenadas de cada partícula, el valor de la velocidad correspondiente.
this.x += this.vx; this.y += this.vy;
Copo.prototype.fueraDelCanvas = function() {
if (this.x >= cw + this.r ||
this.x <= -this.r ||
this.y >= ch + this.r
) {
this.y = -this.r;
this.x = ~~(Math.random()*cw + 1);
} else {
this.x += this.vx;
this.y += this.vy;
}
}
La animación
Hasta ahora lo hemos preparado todo, pero todavía no hay ningún copito de nieve en el array coposRy. Los añadimos uno a uno en cada fotograma, hasta llegar al número máximo de copitos de nieve establecido (numCopos).
if (coposRy.length < numCopos) { var copo = new Copo(); coposRy.push(copo); }
Limpiamos el canvas utilizando el método clearRect().
ctx.clearRect(0, 0, cw, ch);
Después, un bucle for mueve y dibuja uno a uno todos los copos de nieve del array
for (var i = 0; i < coposRy.length; i++) { coposRy[i]. movimiento(); coposRy[i].dibujar(ctx); }
function AnimarCopos() {
el_Id = window.requestAnimationFrame(AnimarCopos);
if (coposRy.length < numCopos) {
var copo = new Copo();
coposRy.push(copo);
}
ctx.clearRect(0, 0, cw, ch);
for (var i = 0; i < coposRy.length; i++) {
coposRy[i]. movimiento();
coposRy[i].dibujar(ctx);
}
}
el_Id = window.requestAnimationFrame(AnimarCopos);
El resultado
Es recomendable abrirlo y manosearlo en codepen.io
See the Pen Nevada de partículas* by Gabi (@enxaneta) on CodePen.