javascript - Canvas 雪动画不起作用

标签 javascript animation canvas

这是一个特定于季节的问题。我制作了一个基本动画来模拟一些雪。问题是雪只下一次,之后屏幕就保持黑色。我遵循了一个教程,将所有内容都放在 window.onload() 中。这对我来说似乎不太好,所以这是我想出的:

let sky, ctx;
let W, H;

const maxSnow = 250;
const snow = [];

function init(){
	sky = document.getElementById("sky");
	ctx = sky.getContext("2d");

	sky.width = W = window.innerWidth;
	sky.height = H = window.innerHeight;

	for(let i = 0; i < maxSnow; i++)
	{
		snow.push({
			x: Math.random()*W, //x-coordinate
			y: -50, //y-coordinate
			radius: Math.random()*4+1, //radius
			density: Math.random()*maxSnow //density
		})
	}
}

function draw()
{
	ctx.clearRect(0, 0, W, H);

	ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
	ctx.beginPath();
	for(let i = 0; i < maxSnow; i++)
	{
		var flake = snow[i];
		ctx.moveTo(flake.x, flake.y);
		ctx.arc(flake.x, flake.y, flake.radius, 0, Math.PI*2, true);
	}
	ctx.fill();
	update();
}

//Function to move the snowflakes
//angle will be an ongoing incremental flag. Sin and Cos functions will be applied to it to create vertical and horizontal movements of the flakes
var angle = 0;
function update()
{
	angle += 0.01;
	for(var i = 0; i < maxSnow; i++)
	{
		var p = snow[i];
		//Updating X and Y coordinates
		//We will add 1 to the cos function to prevent negative values which will lead flakes to move upwards
		//Every particle has its own density which can be used to make the downward movement different for each flake
		//Lets make it more random by adding in the radius
		p.y += Math.cos(angle+p.density) + 1 + p.radius/2;
		p.x += Math.sin(angle) * 2;

		//Sending flakes back from the top when it exits
		//Lets make it a bit more organic and let flakes enter from the left and right also.
		if(p.x > W+5 || p.x < -5 || p.y > H)
		{
			if(i%3 > 0) //66.67% of the flakes
			{
				snow[i] = {x: Math.random()*W, y: -10, r: p.radius, d: p.density};
			}
			else
			{
				//If the flake is exitting from the right
				if(Math.sin(angle) > 0)
				{
					//Enter from the left
					snow[i] = {x: -5, y: Math.random()*H, r: p.radius, d: p.density};
				}
				else
				{
					//Enter from the right
					snow[i] = {x: W+5, y: Math.random()*H, r: p.radius, d: p.density};
				}
			}
		}
	}
}

window.onload = function(){
	init();
	//animation loop
	setInterval(draw, 33);
}

window.addEventListener('resize', function(){
  sky.width = W = window.innerWidth;
  sky.height = H = window.innerHeight;
}, false);
* {
  margin: 0;
  padding: 0;
}

body {
  overflow: hidden;
  background-color: rgba(0, 0, 0, 1);
}
<html>
  <head>
    <link rel="stylesheet" href="style.css">
  </head>

  <body>
    <canvas id="sky"></canvas>
    <script src="snow.js"></script>
  </body>
</html>

有人知道问题是什么以及为什么粒子只下落一次吗? 谢谢。

最佳答案

这是因为当雪花离开屏幕时,您将它们重置为错误的对象。

您的原始对象(和所有方法)需要xyradius密度

但是当您更新对象时,您将创建 xyrd

如果将 rd 重命名为正确的名称,它就可以工作。

let sky, ctx;
let W, H;

const maxSnow = 250;
const snow = [];

function init(){
	sky = document.getElementById("sky");
	ctx = sky.getContext("2d");

	sky.width = W = window.innerWidth;
	sky.height = H = window.innerHeight;

	for(let i = 0; i < maxSnow; i++)
	{
		snow.push({
			x: Math.random()*W, //x-coordinate
			y: -50, //y-coordinate
			radius: Math.random()*4+1, //radius
			density: Math.random()*maxSnow //density
		})
	}
}

function draw()
{
	ctx.clearRect(0, 0, W, H);

	ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
	ctx.beginPath();
	for(let i = 0; i < maxSnow; i++)
	{
		var flake = snow[i];
		ctx.moveTo(flake.x, flake.y);
		ctx.arc(flake.x, flake.y, flake.radius, 0, Math.PI*2, true);
	}
	ctx.fill();
	update();
}

//Function to move the snowflakes
//angle will be an ongoing incremental flag. Sin and Cos functions will be applied to it to create vertical and horizontal movements of the flakes
var angle = 0;
function update()
{
	angle += 0.01;
	for(var i = 0; i < maxSnow; i++)
	{
		var p = snow[i];
		//Updating X and Y coordinates
		//We will add 1 to the cos function to prevent negative values which will lead flakes to move upwards
		//Every particle has its own density which can be used to make the downward movement different for each flake
		//Lets make it more random by adding in the radius
		p.y += Math.cos(angle+p.density) + 1 + p.radius/2;
		p.x += Math.sin(angle) * 2;

		//Sending flakes back from the top when it exits
		//Lets make it a bit more organic and let flakes enter from the left and right also.
		if(p.x > W+5 || p.x < -5 || p.y > H)
		{
			if(i%3 > 0) //66.67% of the flakes
			{
				snow[i] = {x: Math.random()*W, y: -10, radius: p.radius, density: p.density};
			}
			else
			{
				//If the flake is exitting from the right
				if(Math.sin(angle) > 0)
				{
					//Enter from the left
					snow[i] = {x: -5, y: Math.random()*H, radius: p.radius, density: p.density};
				}
				else
				{
					//Enter from the right
					snow[i] = {x: W+5, y: Math.random()*H, radius: p.radius, density: p.density};
				}
			}
		}
	}
}

window.onload = function(){
	init();
	//animation loop
	setInterval(draw, 33);
}

window.addEventListener('resize', function(){
  sky.width = W = window.innerWidth;
  sky.height = H = window.innerHeight;
}, false);
* {
  margin: 0;
  padding: 0;
}

body {
  overflow: hidden;
  background-color: rgba(0, 0, 0, 1);
}
<html>
  <head>
    <link rel="stylesheet" href="style.css">
  </head>

  <body>
    <canvas id="sky"></canvas>
    <script src="snow.js"></script>
  </body>
</html>

关于javascript - Canvas 雪动画不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47701361/

相关文章:

java - 复制 Paint 对象

java - 在屏幕上随机生成一个圆圈,并使其变为绿色或红色

css - 覆盖 canvas woo 主题的移动响应 css

javascript - 使 html 看板可滚动

javascript - 如何在extjs中创建快捷键

javascript - 等待循环与 Promise.all

android - PopupWindow 以编程方式设置动画样式

javascript - 如何在网格列标题上获取可扩展按钮

Android - ActivityOptionsCompat - 自定义展开动画

animation - ECharts 仅禁用符号(marker)动画