HTML5 Canvas 落下的五彩纸屑/雪花多个对象
HTML5 Canvas Falling Confetti / Snow Multiple Objects
我从这个例子开始:http://thecodeplayer.com/walkthrough/html5-canvas-snow-effect
我正在尝试添加多种形状的坠落物体。但是,只有我调用的最后一个似乎有效。它会覆盖屏幕上的其他内容。
我想做的另一件事是从数组中随机化颜色,但是当我添加随机函数时,我得到了疯狂的颜色变化效果。我不完全明白发生了什么,这是我第一次深入 canvas。似乎每帧都在重新绘制对象。这适用于雪,因为它都是白色圆圈。
知道如何进行这些更改吗?这是我的代码(SEIZURE WARNING!):http://codepen.io/paper_matthew/pen/vGpyeq
HTML
<canvas id="confetti"></canvas>
<div id="party-info">
<h2>PARTY!!</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt impedit animi enim iste repellat aliquam laborum consequuntur asperiores neque eos praesentium quis, consectetur cupiditate suscipit cum inventore excepturi? Vel, laudantium.</p>
</div>
CSS
html,
body {
width: 100%;
height: 100%;
margin: 0;
background-color: #fff;
overflow: hidden;
}
#confetti {
position: relative;
top:0;
left: 0;
z-index: 1;
}
#party-info {
position: absolute;
background: #fff;
padding: 20px;
margin: 0 auto;
height: 200px;
top: 0;
left: 0;
right: 0;
bottom:0;
text-align: center;
width: 400px;
z-index: 22;
color: gray;
}
Javascript
window.onload = function() {
//canvas init
var canvas = document.getElementById("confetti");
var ctx = canvas.getContext("2d");
COLORS = [
[238, 96, 169],
[68, 213, 217],
[245, 187, 152],
[144, 148, 188],
[235, 234, 77]
];
//canvas dimensions
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;
//particles
var mp = 100; //max particles
var particles = [];
for (var i = 0; i < mp; i++) {
particles.push({
x: Math.random() * W, //x-coordinate
y: Math.random() * H, //y-coordinate
r: Math.random() * 4 + 1, //radius
d: Math.random() * mp //density
})
}
// Draw the shapes
function drawCircle() {
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = "rgba(" + COLORS[Math.floor(Math.random()*5+0)] + ", 0.8)";
ctx.beginPath();
for (var i = 0; i < mp; i++) {
var p = particles[i];
ctx.moveTo(p.x, p.y);
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2, true);
}
ctx.fill();
update();
}
function drawTriangle() {
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = "rgba(" + COLORS[2] + ", 0.8)";
ctx.beginPath();
for (var i = 0; i < mp; i++) {
var p = particles[i];
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.x + 15, p.y);
ctx.lineTo(p.x + 15, p.y + 15);
ctx.closePath();
}
ctx.fill();
update();
}
function drawLine() {
ctx.clearRect(0, 0, W, H);
ctx.strokeStyle = "rgba(" + COLORS[3] + ", 0.8)";
ctx.beginPath();
for (var i = 0; i < mp; i++) {
var p = particles[i];
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.x, p.y + 20);
ctx.lineWidth = 2;
}
ctx.stroke();
update();
}
function update() {
for (var i = 0; i < mp; i++) {
var p = particles[i];
p.y += Math.cos(p.d) + 1 + p.r / 2;
p.x += Math.sin(0) * 2;
if (p.x > W + 5 || p.x < -5 || p.y > H) {
particles[i] = {
x: Math.random() * W,
y: -10,
r: p.r,
d: p.d
};
}
}
}
function drawShapes() {
drawTriangle();
drawLine();
drawCircle();
}
//animation loop
setInterval(drawShapes, 33);
}
您正在调用 drawShapes(),它会紧接着彼此绘制 3 个形状。 Var ctx 是全局的,所以每次绘制都会立即覆盖前一个。
canvas 的任何动画循环都涉及对 update() 和 draw() 的重复调用。您应该更新您的模型,然后绘制到 canvas。冲洗并重复。
我创建了一个新的 Javascript 文件来配合你的 HTML/CSS。它允许创建一个 Particle 对象,它可以是 3 种类型之一:
- 圆形
- 三角形
- 行
然后我创建了一个包含这些对象类型的数组。每种类型的三分之一填充到数组中。然后,我简单地循环遍历这些对象,并分别在我的更新和绘制函数中的动画循环中调用每个对象的更新和绘制方法。
这是代码,粒子数减少到 40 以提高流畅的动画速度:
function Particle(ctx, width, height, maxParticles, particleType) {
COLORS = [
[238, 96, 169],
[68, 213, 217],
[245, 187, 152],
[144, 148, 188],
[235, 234, 77]
];
var ctx = ctx;
var width = width;
var height = height;
var maxParticles = maxParticles;
var particleType = particleType;
var color = COLORS[Math.floor(Math.random() * 5)];
var x = Math.random() * width;
var y = Math.random() * height;
var r = Math.random() * 4 + 1;
var d = Math.random() * maxParticles;
this.update = function() {
y += Math.cos(d) + 1 + (r / 2);
x += Math.sin(0) * 2;
if (x > width + 5 || x < -5 || y > height) {
x = Math.random() * width;
y = -10;
}
};
this.draw = function() {
ctx.save();
ctx.strokeStyle = "rgba(" + color + ", 0.8)";
ctx.fillStyle = ctx.strokeStyle;
ctx.beginPath();
for (var i = 0; i < maxParticles; i++) {
ctx.moveTo(x, y);
switch (particleType) {
case 1:
ctx.arc(x, y, r, 0, Math.PI * 2, false);
ctx.fill();
break;
case 2:
ctx.lineTo(x + 15, y);
ctx.lineTo(x + 15, y + 15);
ctx.fill();
break;
case 3:
ctx.lineWidth = 2;
ctx.lineTo(x, y + 20);
ctx.stroke();
break;
default:
console.log('Unable to draw: undefined particle type [' + particleType + ']');
break;
}
}
ctx.restore();
};
}
window.onload = function() {
//canvas init
var canvas = document.getElementById("confetti");
var ctx = canvas.getContext("2d");
//canvas dimensions
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;
//particles
var mp = 40;
var particles = [];
for (var i = 0; i < mp; i++) {
var type = Math.floor(i * 3 / mp) + 1;
particles.push(new Particle(ctx, W, H, particles.length, type));
}
function drawShapes() {
update();
draw();
setTimeout(drawShapes, 20);
}
function update() {
for (var key in particles) {
particles[key].update();
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var key in particles) {
particles[key].draw();
}
}
//animation loop
drawShapes();
}
我从这个例子开始:http://thecodeplayer.com/walkthrough/html5-canvas-snow-effect
我正在尝试添加多种形状的坠落物体。但是,只有我调用的最后一个似乎有效。它会覆盖屏幕上的其他内容。
我想做的另一件事是从数组中随机化颜色,但是当我添加随机函数时,我得到了疯狂的颜色变化效果。我不完全明白发生了什么,这是我第一次深入 canvas。似乎每帧都在重新绘制对象。这适用于雪,因为它都是白色圆圈。
知道如何进行这些更改吗?这是我的代码(SEIZURE WARNING!):http://codepen.io/paper_matthew/pen/vGpyeq
HTML
<canvas id="confetti"></canvas>
<div id="party-info">
<h2>PARTY!!</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deserunt impedit animi enim iste repellat aliquam laborum consequuntur asperiores neque eos praesentium quis, consectetur cupiditate suscipit cum inventore excepturi? Vel, laudantium.</p>
</div>
CSS
html,
body {
width: 100%;
height: 100%;
margin: 0;
background-color: #fff;
overflow: hidden;
}
#confetti {
position: relative;
top:0;
left: 0;
z-index: 1;
}
#party-info {
position: absolute;
background: #fff;
padding: 20px;
margin: 0 auto;
height: 200px;
top: 0;
left: 0;
right: 0;
bottom:0;
text-align: center;
width: 400px;
z-index: 22;
color: gray;
}
Javascript
window.onload = function() {
//canvas init
var canvas = document.getElementById("confetti");
var ctx = canvas.getContext("2d");
COLORS = [
[238, 96, 169],
[68, 213, 217],
[245, 187, 152],
[144, 148, 188],
[235, 234, 77]
];
//canvas dimensions
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;
//particles
var mp = 100; //max particles
var particles = [];
for (var i = 0; i < mp; i++) {
particles.push({
x: Math.random() * W, //x-coordinate
y: Math.random() * H, //y-coordinate
r: Math.random() * 4 + 1, //radius
d: Math.random() * mp //density
})
}
// Draw the shapes
function drawCircle() {
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = "rgba(" + COLORS[Math.floor(Math.random()*5+0)] + ", 0.8)";
ctx.beginPath();
for (var i = 0; i < mp; i++) {
var p = particles[i];
ctx.moveTo(p.x, p.y);
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2, true);
}
ctx.fill();
update();
}
function drawTriangle() {
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = "rgba(" + COLORS[2] + ", 0.8)";
ctx.beginPath();
for (var i = 0; i < mp; i++) {
var p = particles[i];
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.x + 15, p.y);
ctx.lineTo(p.x + 15, p.y + 15);
ctx.closePath();
}
ctx.fill();
update();
}
function drawLine() {
ctx.clearRect(0, 0, W, H);
ctx.strokeStyle = "rgba(" + COLORS[3] + ", 0.8)";
ctx.beginPath();
for (var i = 0; i < mp; i++) {
var p = particles[i];
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.x, p.y + 20);
ctx.lineWidth = 2;
}
ctx.stroke();
update();
}
function update() {
for (var i = 0; i < mp; i++) {
var p = particles[i];
p.y += Math.cos(p.d) + 1 + p.r / 2;
p.x += Math.sin(0) * 2;
if (p.x > W + 5 || p.x < -5 || p.y > H) {
particles[i] = {
x: Math.random() * W,
y: -10,
r: p.r,
d: p.d
};
}
}
}
function drawShapes() {
drawTriangle();
drawLine();
drawCircle();
}
//animation loop
setInterval(drawShapes, 33);
}
您正在调用 drawShapes(),它会紧接着彼此绘制 3 个形状。 Var ctx 是全局的,所以每次绘制都会立即覆盖前一个。
canvas 的任何动画循环都涉及对 update() 和 draw() 的重复调用。您应该更新您的模型,然后绘制到 canvas。冲洗并重复。
我创建了一个新的 Javascript 文件来配合你的 HTML/CSS。它允许创建一个 Particle 对象,它可以是 3 种类型之一:
- 圆形
- 三角形
- 行
然后我创建了一个包含这些对象类型的数组。每种类型的三分之一填充到数组中。然后,我简单地循环遍历这些对象,并分别在我的更新和绘制函数中的动画循环中调用每个对象的更新和绘制方法。
这是代码,粒子数减少到 40 以提高流畅的动画速度:
function Particle(ctx, width, height, maxParticles, particleType) {
COLORS = [
[238, 96, 169],
[68, 213, 217],
[245, 187, 152],
[144, 148, 188],
[235, 234, 77]
];
var ctx = ctx;
var width = width;
var height = height;
var maxParticles = maxParticles;
var particleType = particleType;
var color = COLORS[Math.floor(Math.random() * 5)];
var x = Math.random() * width;
var y = Math.random() * height;
var r = Math.random() * 4 + 1;
var d = Math.random() * maxParticles;
this.update = function() {
y += Math.cos(d) + 1 + (r / 2);
x += Math.sin(0) * 2;
if (x > width + 5 || x < -5 || y > height) {
x = Math.random() * width;
y = -10;
}
};
this.draw = function() {
ctx.save();
ctx.strokeStyle = "rgba(" + color + ", 0.8)";
ctx.fillStyle = ctx.strokeStyle;
ctx.beginPath();
for (var i = 0; i < maxParticles; i++) {
ctx.moveTo(x, y);
switch (particleType) {
case 1:
ctx.arc(x, y, r, 0, Math.PI * 2, false);
ctx.fill();
break;
case 2:
ctx.lineTo(x + 15, y);
ctx.lineTo(x + 15, y + 15);
ctx.fill();
break;
case 3:
ctx.lineWidth = 2;
ctx.lineTo(x, y + 20);
ctx.stroke();
break;
default:
console.log('Unable to draw: undefined particle type [' + particleType + ']');
break;
}
}
ctx.restore();
};
}
window.onload = function() {
//canvas init
var canvas = document.getElementById("confetti");
var ctx = canvas.getContext("2d");
//canvas dimensions
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;
//particles
var mp = 40;
var particles = [];
for (var i = 0; i < mp; i++) {
var type = Math.floor(i * 3 / mp) + 1;
particles.push(new Particle(ctx, W, H, particles.length, type));
}
function drawShapes() {
update();
draw();
setTimeout(drawShapes, 20);
}
function update() {
for (var key in particles) {
particles[key].update();
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var key in particles) {
particles[key].draw();
}
}
//animation loop
drawShapes();
}