javascript - JavaScript - 画布下雪动画
问题描述
我想在 JavaScript 中创建下雪动画效果。我对这种编码语言的知识真的很差。但是,我设法用一片雪花和一个循环来做到这一点。
我现在想生成不止一个雪花。有人可以帮我弄清楚如何产生更多的雪花吗?
let canvas = document.getElementById("wip");
let ctx = canvas.getContext("2d");
canvas.width = window.innerWidth-30;
canvas.height = window.innerHeight-30;
let xloc = Math.floor(Math.random() * canvas.width);
let yloc = 0;
ctx.strokeStyle="#"+((1<<24)*Math.random()|0).toString(16);
function drawflake(){
ctx.beginPath();
//Top Right Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc-7,yloc-7);
ctx.lineTo(xloc-11,yloc-7);
ctx.moveTo(xloc-7,yloc-7);
ctx.lineTo(xloc-7,yloc-11);
ctx.moveTo(xloc-7,yloc-7);
ctx.lineTo(xloc-14,yloc-14);
ctx.lineTo(xloc-17,yloc-14);
ctx.moveTo(xloc-14,yloc-14);
ctx.lineTo(xloc-14,yloc-17);
ctx.moveTo(xloc-14,yloc-14);
ctx.lineTo(xloc-18,yloc-18);
//Top Left Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc+7,yloc-7);
ctx.lineTo(xloc+11,yloc-7);
ctx.moveTo(xloc+7,yloc-7);
ctx.lineTo(xloc+7,yloc-11);
ctx.moveTo(xloc+7,yloc-7);
ctx.lineTo(xloc+14,yloc-14);
ctx.lineTo(xloc+17,yloc-14);
ctx.moveTo(xloc+14,yloc-14);
ctx.lineTo(xloc+14,yloc-17);
ctx.moveTo(xloc+14,yloc-14);
ctx.lineTo(xloc+18,yloc-18);
//Bottom Left Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc+7,yloc+7);
ctx.lineTo(xloc+7,yloc+11);
ctx.moveTo(xloc+7,yloc+7);
ctx.lineTo(xloc+11,yloc+7);
ctx.moveTo(xloc+7,yloc+7);
ctx.lineTo(xloc+14,yloc+14);
ctx.lineTo(xloc+14,yloc+17);
ctx.moveTo(xloc+14,yloc+14);
ctx.lineTo(xloc+17,yloc+14);
ctx.moveTo(xloc+14,yloc+14);
ctx.lineTo(xloc+18,yloc+18);
//Bottom Right Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc-7,yloc+7);
ctx.lineTo(xloc-11,yloc+7);
ctx.moveTo(xloc-7,yloc+7);
ctx.lineTo(xloc-7,yloc+11);
ctx.moveTo(xloc-7,yloc+7);
ctx.lineTo(xloc-14,yloc+14);
ctx.lineTo(xloc-17,yloc+14);
ctx.moveTo(xloc-14,yloc+14);
ctx.lineTo(xloc-14,yloc+17);
ctx.moveTo(xloc-14,yloc+14);
ctx.lineTo(xloc-18,yloc+18);
//Left Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc-9.899,yloc);
ctx.lineTo(xloc-12.899,yloc-3);
ctx.moveTo(xloc-9.899,yloc);
ctx.lineTo(xloc-12.899,yloc+3);
ctx.moveTo(xloc-9.899,yloc);
ctx.lineTo(xloc-19.799,yloc);
ctx.lineTo(xloc-22.799,yloc-3);
ctx.moveTo(xloc-19.799,yloc);
ctx.lineTo(xloc-22.799,yloc+3);
ctx.moveTo(xloc-19.799,yloc);
ctx.lineTo(xloc-25.456,yloc);
//Right Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc+9.899,yloc);
ctx.lineTo(xloc+12.899,yloc-3);
ctx.moveTo(xloc+9.899,yloc);
ctx.lineTo(xloc+12.899,yloc+3);
ctx.moveTo(xloc+9.899,yloc);
ctx.lineTo(xloc+19.799,yloc);
ctx.lineTo(xloc+22.799,yloc-3);
ctx.moveTo(xloc+19.799,yloc);
ctx.lineTo(xloc+22.799,yloc+3);
ctx.moveTo(xloc+19.799,yloc);
ctx.lineTo(xloc+25.456,yloc);
ctx.lineWidth = 1;
ctx.lineCap = 'round';
ctx.stroke();
yloc=yloc+1;
if (yloc>canvas.height) {
yloc=0;
xloc = Math.floor(Math.random() * canvas.width);
ctx.strokeStyle="#"+((1<<24)*Math.random()|0).toString(16);
}
}
function clearCanvas() {
ctx.clearRect(0,0, canvas.width, canvas.height);
}
function repeat() {
clearCanvas();
drawflake();
setTimeout(repeat, 24);
}
repeat();
<canvas id="wip"></canvas>
解决方案
您可以将所有特定于 flake 的代码移动到 aclass
中,以便您可以使用new
. 定义薄片属性的变量应定义为实例属性。在这种情况下,您需要对变量xloc
和yloc
进行更改strokeStyle
。尽管后者是 的一个属性ctx
,但每次显示另一个薄片时,该属性都需要更改,因此薄片必须知道自己的颜色是什么。所以这需要是一个属性。
然后我建议删除将薄片移回顶部的代码,因为这确实应该被视为不同的薄片。所以销毁前一个实例并创建一个新实例更有意义。
另一个异步循环(也有setTimeout
,但会有更大的延迟)可以负责创建新的薄片。
以下是您的代码如何适应这种情况。评论澄清了我所做的所有更改:
let canvas = document.getElementById("wip");
let ctx = canvas.getContext("2d");
canvas.width = window.innerWidth-30;
canvas.height = window.innerHeight-30;
class SnowFlake { // each snowflake will be an instance of this class
constructor() { // this is called when you do `new SnowFlake()`
// the location is now saved in variables that belong to the instance:
// Note the use of `this` in all three assignments:
this.xloc = Math.floor(Math.random() * canvas.width);
this.yloc = 0;
this.strokeStyle="#"+((1<<24)*Math.random()|0).toString(16);
}
drawflake(){ // This function becomes a method
// Get the stroke style that was saved during construction:
ctx.strokeStyle=this.strokeStyle;
// Get the location that was saved during construction
let xloc = this.xloc;
let yloc = this.yloc;
// No change needed in the drawing part of this function...
ctx.beginPath();
//Top Right Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc-7,yloc-7);
ctx.lineTo(xloc-11,yloc-7);
ctx.moveTo(xloc-7,yloc-7);
ctx.lineTo(xloc-7,yloc-11);
ctx.moveTo(xloc-7,yloc-7);
ctx.lineTo(xloc-14,yloc-14);
ctx.lineTo(xloc-17,yloc-14);
ctx.moveTo(xloc-14,yloc-14);
ctx.lineTo(xloc-14,yloc-17);
ctx.moveTo(xloc-14,yloc-14);
ctx.lineTo(xloc-18,yloc-18);
//Top Left Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc+7,yloc-7);
ctx.lineTo(xloc+11,yloc-7);
ctx.moveTo(xloc+7,yloc-7);
ctx.lineTo(xloc+7,yloc-11);
ctx.moveTo(xloc+7,yloc-7);
ctx.lineTo(xloc+14,yloc-14);
ctx.lineTo(xloc+17,yloc-14);
ctx.moveTo(xloc+14,yloc-14);
ctx.lineTo(xloc+14,yloc-17);
ctx.moveTo(xloc+14,yloc-14);
ctx.lineTo(xloc+18,yloc-18);
//Bottom Left Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc+7,yloc+7);
ctx.lineTo(xloc+7,yloc+11);
ctx.moveTo(xloc+7,yloc+7);
ctx.lineTo(xloc+11,yloc+7);
ctx.moveTo(xloc+7,yloc+7);
ctx.lineTo(xloc+14,yloc+14);
ctx.lineTo(xloc+14,yloc+17);
ctx.moveTo(xloc+14,yloc+14);
ctx.lineTo(xloc+17,yloc+14);
ctx.moveTo(xloc+14,yloc+14);
ctx.lineTo(xloc+18,yloc+18);
//Bottom Right Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc-7,yloc+7);
ctx.lineTo(xloc-11,yloc+7);
ctx.moveTo(xloc-7,yloc+7);
ctx.lineTo(xloc-7,yloc+11);
ctx.moveTo(xloc-7,yloc+7);
ctx.lineTo(xloc-14,yloc+14);
ctx.lineTo(xloc-17,yloc+14);
ctx.moveTo(xloc-14,yloc+14);
ctx.lineTo(xloc-14,yloc+17);
ctx.moveTo(xloc-14,yloc+14);
ctx.lineTo(xloc-18,yloc+18);
//Left Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc-9.899,yloc);
ctx.lineTo(xloc-12.899,yloc-3);
ctx.moveTo(xloc-9.899,yloc);
ctx.lineTo(xloc-12.899,yloc+3);
ctx.moveTo(xloc-9.899,yloc);
ctx.lineTo(xloc-19.799,yloc);
ctx.lineTo(xloc-22.799,yloc-3);
ctx.moveTo(xloc-19.799,yloc);
ctx.lineTo(xloc-22.799,yloc+3);
ctx.moveTo(xloc-19.799,yloc);
ctx.lineTo(xloc-25.456,yloc);
//Right Brunch
ctx.moveTo(xloc,yloc);
ctx.lineTo(xloc+9.899,yloc);
ctx.lineTo(xloc+12.899,yloc-3);
ctx.moveTo(xloc+9.899,yloc);
ctx.lineTo(xloc+12.899,yloc+3);
ctx.moveTo(xloc+9.899,yloc);
ctx.lineTo(xloc+19.799,yloc);
ctx.lineTo(xloc+22.799,yloc-3);
ctx.moveTo(xloc+19.799,yloc);
ctx.lineTo(xloc+22.799,yloc+3);
ctx.moveTo(xloc+19.799,yloc);
ctx.lineTo(xloc+25.456,yloc);
ctx.lineWidth = 1;
ctx.lineCap = 'round';
ctx.stroke();
// Save the new location to the instance:
this.yloc = yloc+1;
// Don't deal here with the range check. Do that in `repeat`
}
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
// Collection that holds all of the active flakes
let flakes = new Set;
function repeat() {
clearCanvas();
// Draw all flakes
for (let flake of flakes) {
flake.drawflake();
if (flake.yloc > canvas.height) { // flake reached the bottom?
flakes.delete(flake); // remove the flake from the collection
}
}
setTimeout(repeat, 24);
}
// new function to deal with the generation of new flakes
function generate() {
flakes.add(new SnowFlake()); // construct a new flake and add it to the collection
// Make the time between two generations of a new flakes a bit random
setTimeout(generate, 1000 + Math.random() * 2000);
}
generate(); // also start the generations
repeat();
<canvas id="wip"></canvas>
您可以通过更改表达式中使用的两个常数来影响薄片生成的速率及其变化1000 + Math.random() * 2000
。
推荐阅读
- r - 使用输入在 Shiny 中分配名称
- batch-file - Windows 批量比较固定日期和当前日期
- qt - 是否可以直接使用 QtDesigner 实现独立于分辨率的 UI?
- javascript - 为什么我收到错误“Uncaught TypeError: Cannot read property 'style' of undefined at HTMLLIElement.”?
- python - 将 Sentinel-1 SAR 图像的地理坐标(经纬度)转换为像素位置 (x,y)
- selenium-webdriver - 即使在调试时我发现它找到了正确的元素,Webdriverwait 也会导致超时
- excel - 循环遍历另一个 Excel 工作表上的值
- php - 如何使用ajax将数据从动态添加的表单发送到php
- java - 重启后如何发送通知?
- c# - 如何在 msbuild 内联任务中使用 C# 6 语法?