Reputation: 155
So a season specific question. I have made a basic animation to simulate some snow. The problem is that the snow only falls once and the screen stays black after that. I have followed a tutorial which put everything inside the window.onload(). THis seems not as good style to me so here is what i came up with:
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>
Does anybody see what the problem is and why the particles are only falling once? Thank you.
Upvotes: 2
Views: 205
Reputation: 196217
The is because when the snow flakes exit the screen you reset them to a wrong object.
You original object (and all methods) expect x
,y
,radius
and density
But when you update the object you create x
,y
, r
and d
.
If you rename r
and d
to the correct names it works.
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>
Upvotes: 3