【问题标题】:Creating Falling Snow using HTML 5 and JS使用 HTML 5 和 JS 创建飘雪
【发布时间】:2012-12-08 15:46:44
【问题描述】:

我参观了Stack Exchange Winter Bash website,我喜欢飘落的雪花!我的问题是,我怎样才能重新创建一个看起来一样好的类似效果。我试图对代码进行逆向工程,看看我是否能弄清楚,但可惜没有运气。 JS 在我头上。我做了一些谷歌搜索,发现了一些examples,但它们不如 SE 网站优雅或看起来不太好。

谁能提供一些关于如何复制 SE Winter Bash 网站创建的内容或我可以学习如何执行此操作的地方的说明?

编辑:我想尽可能接近地复制效果,即:雪花飘落,并且能够移动鼠标并使雪随着鼠标的瞬间移动或旋转.

【问题讨论】:

  • 看起来他正在接受错误的答案:P
  • @j08691 - 继续发布他们是如何做到的。如果您想添加一些提示并且一些自己动手做的想法,那就去做吧。 =>
  • @Bergi - 我说我从其他代码中剔除了雪代码,但我从未说过我设法理解或取消缩小它。这可能需要几天时间! :)
  • @j08691:将其发布为 wiki 答案,让我们看看我们能做些什么 :-)
  • 仅供参考,我计划将 winterba.sh snow 的东西作为开源发布。有时间我会更新的。

标签: javascript html canvas


【解决方案1】:

很好的问题,实际上我前段时间写了一个雪插件,我会不断更新see it in actionAlso a link to the pure js source

我注意到您标记了问题 html5 和 canvas,但是您可以不使用任何一个,而只需使用带有图像或不同背景颜色的标准元素。

这是我刚才放在一起的两个非常简单的方法,供您使用。在我看来,关键是使用 sin 在薄片掉落时获得漂亮的波浪效果。第一个使用 canvas 元素,第二个使用常规 dom 元素。

因为我完全沉迷于画布,所以这里有一个画布版本,在我看来表现相当不错。

Canvas version

Full Screen

(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();​

Standard element version

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));
}​

【讨论】:

  • 感谢您的信息!然而,小提琴中没有下雪!我看到雪花在最顶端移动,但没有下雪。
  • 真的吗?你使用的是什么浏览器?它可以在 Chrome 中使用,尽管我没有与其他任何人进行测试。
  • 嘿,下雪了!现在你可以让雪落下并堆成一个雪人吗?...哈,哈,哈...开个玩笑=>
  • 这太酷了。我将在假期期间在我们的网站上运行它。有趣的想法。感谢分享!
  • 您的“标准版本”中有错误。在检查 flake.x > body width 时,将 flake.y 设置为 0 而不是 flake.x。这会导致奇怪的滚动问题。固定在这里:jsfiddle.net/7WH3a
【解决方案2】:

我已经创建了一个纯 HTML 5 和 js 降雪。 在这里查看我的代码笔:https://codepen.io/onlintool24/pen/GRMOBVo

// Amount of Snowflakes
var snowMax = 35;

// Snowflake Colours
var snowColor = ["#DDD", "#EEE"];

// Snow Entity
var snowEntity = "&#x2022;";

// Falling Velocity
var snowSpeed = 0.75;

// Minimum Flake Size
var snowMinSize = 8;

// Maximum Flake Size
var snowMaxSize = 24;

// Refresh Rate (in milliseconds)
var snowRefresh = 50;

// Additional Styles
var snowStyles = "cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none;";

/*
// End of Configuration
// ----------------------------------------
// Do not modify the code below this line
*/

var snow = [],
    pos = [],
    coords = [],
    lefr = [],
    marginBottom,
    marginRight;

function randomise(range) {
    rand = Math.floor(range * Math.random());
    return rand;
}

function initSnow() {
    var snowSize = snowMaxSize - snowMinSize;
    marginBottom = document.body.scrollHeight - 5;
    marginRight = document.body.clientWidth - 15;

    for (i = 0; i <= snowMax; i++) {
        coords[i] = 0;
        lefr[i] = Math.random() * 15;
        pos[i] = 0.03 + Math.random() / 10;
        snow[i] = document.getElementById("flake" + i);
        snow[i].style.fontFamily = "inherit";
        snow[i].size = randomise(snowSize) + snowMinSize;
        snow[i].style.fontSize = snow[i].size + "px";
        snow[i].style.color = snowColor[randomise(snowColor.length)];
        snow[i].style.zIndex = 1000;
        snow[i].sink = snowSpeed * snow[i].size / 5;
        snow[i].posX = randomise(marginRight - snow[i].size);
        snow[i].posY = randomise(2 * marginBottom - marginBottom - 2 * snow[i].size);
        snow[i].style.left = snow[i].posX + "px";
        snow[i].style.top = snow[i].posY + "px";
    }

    moveSnow();
}

function resize() {
    marginBottom = document.body.scrollHeight - 5;
    marginRight = document.body.clientWidth - 15;
}

function moveSnow() {
    for (i = 0; i <= snowMax; i++) {
        coords[i] += pos[i];
        snow[i].posY += snow[i].sink;
        snow[i].style.left = snow[i].posX + lefr[i] * Math.sin(coords[i]) + "px";
        snow[i].style.top = snow[i].posY + "px";

        if (snow[i].posY >= marginBottom - 2 * snow[i].size || parseInt(snow[i].style.left) > (marginRight - 3 * lefr[i])) {
            snow[i].posX = randomise(marginRight - snow[i].size);
            snow[i].posY = 0;
        }
    }

    setTimeout("moveSnow()", snowRefresh);
}

for (i = 0; i <= snowMax; i++) {
    document.write("<span id='flake" + i + "' style='" + snowStyles + "position:absolute;top:-" + snowMaxSize + "'>" + snowEntity + "</span>");
}

window.addEventListener('resize', resize);
window.addEventListener('load', initSnow);
body{
  background: skyblue;
  height:100%;
  width:100%;
    display:block;
  position:relative;
}
&lt;span id="flake0" style="cursor: default; user-select: none; position: absolute; font-family: inherit; font-size: 19px; color: rgb(221, 221, 221); z-index: 1000; left: 226px; top: 561px;"&gt;•&lt;/span&gt;

【讨论】:

    【解决方案3】:

    飘落的雪花很简单:创建一个画布,创建一堆雪花,然后绘制它们。

    你可以像这样创建一个雪花类:

    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;
    }
    

    或者类似的东西。然后你有一个计时器,每一步都会少量调整每个雪花的方向,然后通过考虑速度和方向来计算新的 X 和 Y。

    很难解释,但实际上很基本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-24
      • 2021-04-17
      • 1970-01-01
      • 1970-01-01
      • 2021-05-10
      相关资源
      最近更新 更多