37 votes

Création de chutes de neige avec HTML 5 et JS

J'ai visité le Site web du Stack Exchange Winter Bash et j'adore la neige qui tombe ! Ma question est la suivante : comment puis-je recréer un effet similaire qui soit aussi joli ? J'ai essayé de faire de l'ingénierie inverse sur le code pour voir si je pouvais le comprendre, mais hélas pas de chance. Le JS est au-dessus de ma tête. J'ai fait un peu de recherche sur Google et je suis tombé sur un site de exemples mais ils n'étaient pas aussi élégants que le site SE ou n'avaient pas un très bon aspect.

Quelqu'un peut-il fournir des instructions sur la façon de reproduire ce que le site SE Winter Bash crée ou un endroit où je pourrais apprendre à le faire ?

Edit : J'aimerais reproduire l'effet le plus proche possible, c'est-à-dire la neige qui tombe avec des flocons de neige, et pouvoir déplacer la souris et faire bouger ou tourbillonner la neige à chaque instant.

52voto

Loktar Points 17625

Bonne question, j'ai en fait écrit un plugin pour la neige il y a un certain temps que je mets à jour continuellement. voyez-le en action . Egalement un lien vers la source pure js

J'ai remarqué que vous avez marqué la question html5 et canvas, cependant vous pouvez le faire sans utiliser l'un ou l'autre, et juste des éléments standards avec des images ou des couleurs de fond différentes.

En voici deux, très simples, que je viens de créer pour que vous puissiez les utiliser. La clé, à mon avis, est d'utiliser le péché pour obtenir un bel effet ondulé lorsque les flocons tombent. Le premier utilise l'élément canvas, le second les éléments dom ordinaires.

Comme je suis absolument accro à la toile, voici une version en toile qui, à mon avis, se comporte plutôt bien.

Version toile

Plein écran

(function() {
    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
    function(callback) {
        window.setTimeout(callback, 1000 / 60);
    };
    window.requestAnimationFrame = requestAnimationFrame;
})();

var flakes = [],
    canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    flakeCount = 200,
    mX = -100,
    mY = -100

    canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function snow() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    for (var i = 0; i < flakeCount; i++) {
        var flake = flakes[i],
            x = mX,
            y = mY,
            minDist = 150,
            x2 = flake.x,
            y2 = flake.y;

        var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)),
            dx = x2 - x,
            dy = y2 - y;

        if (dist < minDist) {
            var force = minDist / (dist * dist),
                xcomp = (x - x2) / dist,
                ycomp = (y - y2) / dist,
                deltaV = force / 2;

            flake.velX -= deltaV * xcomp;
            flake.velY -= deltaV * ycomp;

        } else {
            flake.velX *= .98;
            if (flake.velY <= flake.speed) {
                flake.velY = flake.speed
            }
            flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
        }

        ctx.fillStyle = "rgba(255,255,255," + flake.opacity + ")";
        flake.y += flake.velY;
        flake.x += flake.velX;

        if (flake.y >= canvas.height || flake.y <= 0) {
            reset(flake);
        }

        if (flake.x >= canvas.width || flake.x <= 0) {
            reset(flake);
        }

        ctx.beginPath();
        ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2);
        ctx.fill();
    }
    requestAnimationFrame(snow);
};

function reset(flake) {
    flake.x = Math.floor(Math.random() * canvas.width);
    flake.y = 0;
    flake.size = (Math.random() * 3) + 2;
    flake.speed = (Math.random() * 1) + 0.5;
    flake.velY = flake.speed;
    flake.velX = 0;
    flake.opacity = (Math.random() * 0.5) + 0.3;
}

function init() {
    for (var i = 0; i < flakeCount; i++) {
        var x = Math.floor(Math.random() * canvas.width),
            y = Math.floor(Math.random() * canvas.height),
            size = (Math.random() * 3) + 2,
            speed = (Math.random() * 1) + 0.5,
            opacity = (Math.random() * 0.5) + 0.3;

        flakes.push({
            speed: speed,
            velY: speed,
            velX: 0,
            x: x,
            y: y,
            size: size,
            stepSize: (Math.random()) / 30,
            step: 0,
            angle: 180,
            opacity: opacity
        });
    }

    snow();
};

canvas.addEventListener("mousemove", function(e) {
    mX = e.clientX,
    mY = e.clientY
});

init();​

Version de l'élément standard

var flakes = [],
    bodyHeight = getDocHeight(),
    bodyWidth = document.body.offsetWidth;

function snow() {
    for (var i = 0; i < 50; i++) {
        var flake = flakes[i];

        flake.y += flake.velY;

        if (flake.y > bodyHeight - (flake.size + 6)) {
            flake.y = 0;
        }

        flake.el.style.top = flake.y + 'px';
        flake.el.style.left = ~~flake.x + 'px';

        flake.step += flake.stepSize;
        flake.velX = Math.cos(flake.step);

        flake.x += flake.velX;

        if (flake.x > bodyWidth - 40 || flake.x < 30) {
            flake.y = 0;
        }
    }
    setTimeout(snow, 10);
};

function init() {
    var docFrag = document.createDocumentFragment();
    for (var i = 0; i < 50; i++) {
        var flake = document.createElement("div"),
            x = Math.floor(Math.random() * bodyWidth),
            y = Math.floor(Math.random() * bodyHeight),
            size = (Math.random() * 5) + 2,
            speed = (Math.random() * 1) + 0.5;

        flake.style.width = size + 'px';
        flake.style.height = size + 'px';
        flake.style.background = "#fff";

        flake.style.left = x + 'px';
        flake.style.top = y;
        flake.classList.add("flake");

        flakes.push({
            el: flake,
            speed: speed,
            velY: speed,
            velX: 0,
            x: x,
            y: y,
            size: 2,
            stepSize: (Math.random() * 5) / 100,
            step: 0
        });
        docFrag.appendChild(flake);
    }

    document.body.appendChild(docFrag);
    snow();
};

document.addEventListener("mousemove", function(e) {
    var x = e.clientX,
        y = e.clientY,
        minDist = 150;

    for (var i = 0; i < flakes.length; i++) {
        var x2 = flakes[i].x,
            y2 = flakes[i].y;

        var dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));

        if (dist < minDist) {
            rad = Math.atan2(y2, x2), angle = rad / Math.PI * 180;

            flakes[i].velX = (x2 / dist) * 0.2;
            flakes[i].velY = (y2 / dist) * 0.2;

            flakes[i].x += flakes[i].velX;
            flakes[i].y += flakes[i].velY;
        } else {
            flakes[i].velY *= 0.9;
            flakes[i].velX
            if (flakes[i].velY <= flakes[i].speed) {
                flakes[i].velY = flakes[i].speed;
            }
        }
    }
});

init();

function getDocHeight() {
    return Math.max(
    Math.max(document.body.scrollHeight, document.documentElement.scrollHeight), Math.max(document.body.offsetHeight, document.documentElement.offsetHeight), Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}​

-6voto

Niet the Dark Absol Points 154811

La neige qui tombe est simple : Créez une toile, créez un tas de flocons de neige, dessinez-les.

Vous pouvez créer une classe flocon de neige comme suit :

function Snowflake() {
    this.x = Math.random()*canvas.width;
    this.y = -16;
    this.speed = Math.random()*3+1;
    this.direction = Math.random()*360;
    this.maxSpeed = 4;
}

Ou quelque chose comme ça. Ensuite, vous avez une minuterie qui, à chaque étape, ajuste la direction de chaque flocon de neige d'une petite quantité, puis calcule ses nouveaux X et Y en factorisant la vitesse et la direction.

C'est difficile à expliquer, mais en fait assez basique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X