为了模拟烟花绽放的动画效果,我们可以设计两个类:Firework
和Particle
。Firework
类代表烟花本身,而Particle
类代表烟花爆炸后产生的碎片。
Firework
类用于控制烟花的更新、爆照效果、绘制功能。在这个类中,update
方法用于更新烟花的位置,并在适当的时机触发爆炸。draw
方法用于在画布上绘制烟花。explode
方法用于创建爆炸效果,生成多个Particle
对象。
function Firework()
{
//this.x = canvas.width/4*(1+3*Math.random());
//this.y = canvas.height - 15;
this.x=Math.random() * width;
this.y=Math.random() * height;
this.angle = Math.random() * Math.PI / 4 - Math.PI / 6;
this.xSpeed = Math.sin(this.angle) *(6+Math.random()*7);
this.ySpeed = -Math.cos(this.angle) *(6+Math.random()*7);
this.hue = Math.floor(Math.random() * 360);
}
Firework.prototype.draw= function()
{
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(Math.atan2(this.ySpeed, this.xSpeed) + Math.PI / 2);
ctx.fillStyle =`hsl(${this.hue}, 100%, 50%)`;
ctx.fillRect(0, 0, 5, 15);
ctx.restore();
}
Firework.prototype.update= function()
{
this.x = this.x + this.xSpeed;
this.y = this.y + this.ySpeed;
this.ySpeed += 0.1;
}
Firework.prototype.explode= function()
{
for (var i = 0; i < 70; i++)
{
particles.push(new Particle(this.x, this.y, this.hue));
}
}
Particle类
定义2个方法:绘制碎片散开轨迹的方法draw()、碎片散开时坐标改变方法update()。碎片散开时逐渐变小(属性size值减量),当size值小于1时,从碎片数组中删除该碎片,表示碎片已消亡。
function Particle(x,y,hue)
{
this.x = x;
this.y = y;
this.hue = hue;
this.lightness = 50;
this.size = 15 + Math.random() * 10;
this.angle = Math.random() * 2 * Math.PI;
this.xSpeed = Math.cos(this.angle) *(1+Math.random() * 6);
this.ySpeed = Math.sin(this.angle) *(1+Math.random() * 6);
}
Particle.prototype.draw= function()
{
ctx.fillStyle = `hsl(${this.hue}, 100%, ${this.lightness}%)`;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
}
Particle.prototype.update= function(index)
{
this.ySpeed += 0.05;
this.size = this.size*0.95;
this.x = this.x + this.xSpeed;
this.y = this.y + this.ySpeed;
if (this.size<1)
{
particles.splice(index,1);
}
}
最后添加循环操作:
function loop()
{
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.fillRect(0,0,canvas.width,canvas.height);
counter++;
if (counter==15)
{
fireworks.push(new Firework());
counter=0;
}
var i=fireworks.length;
while (i--)
{
fireworks[i].draw();
fireworks[i].update();
if (fireworks[i].ySpeed > 0)
{
fireworks[i].explode();
fireworks.splice(i, 1);
}
}
var i=particles.length;
while (i--)
{
particles[i].draw();
particles[i].update(i);
}
requestAnimationFrame(loop);
}
完成代码如下:
<html>
<head>
<title>烟花绽放</title>
<style>
canvas {
position: absolute;
width: 100%;
height: 100%;
background:black;
}
</style>
</head>
<body>
<canvas id="myCanvas"></canvas>
<script type="text/javascript">
var canvas=document.getElementById('myCanvas');
ctx= canvas.getContext('2d');
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;
var fireworks=[];
var particles=[];
var counter = 0;
function Firework()
{
//this.x = canvas.width/4*(1+3*Math.random());
//this.y = canvas.height - 15;
this.x=Math.random() * width;
this.y=Math.random() * height;
this.angle = Math.random() * Math.PI / 4 - Math.PI / 6;
this.xSpeed = Math.sin(this.angle) *(6+Math.random()*7);
this.ySpeed = -Math.cos(this.angle) *(6+Math.random()*7);
this.hue = Math.floor(Math.random() * 360);
}
Firework.prototype.draw= function()
{
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(Math.atan2(this.ySpeed, this.xSpeed) + Math.PI / 2);
ctx.fillStyle =`hsl(${this.hue}, 100%, 50%)`;
ctx.fillRect(0, 0, 5, 15);
ctx.restore();
}
Firework.prototype.update= function()
{
this.x = this.x + this.xSpeed;
this.y = this.y + this.ySpeed;
this.ySpeed += 0.1;
}
Firework.prototype.explode= function()
{
for (var i = 0; i < 70; i++)
{
particles.push(new Particle(this.x, this.y, this.hue));
}
}
function Particle(x,y,hue)
{
this.x = x;
this.y = y;
this.hue = hue;
this.lightness = 50;
this.size = 15 + Math.random() * 10;
this.angle = Math.random() * 2 * Math.PI;
this.xSpeed = Math.cos(this.angle) *(1+Math.random() * 6);
this.ySpeed = Math.sin(this.angle) *(1+Math.random() * 6);
}
Particle.prototype.draw= function()
{
ctx.fillStyle = `hsl(${this.hue}, 100%, ${this.lightness}%)`;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
}
Particle.prototype.update= function(index)
{
this.ySpeed += 0.05;
this.size = this.size*0.95;
this.x = this.x + this.xSpeed;
this.y = this.y + this.ySpeed;
if (this.size<1)
{
particles.splice(index,1);
}
}
function loop()
{
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.fillRect(0,0,canvas.width,canvas.height);
counter++;
if (counter==15)
{
fireworks.push(new Firework());
counter=0;
}
var i=fireworks.length;
while (i--)
{
fireworks[i].draw();
fireworks[i].update();
if (fireworks[i].ySpeed > 0)
{
fireworks[i].explode();
fireworks.splice(i, 1);
}
}
var i=particles.length;
while (i--)
{
particles[i].draw();
particles[i].update(i);
}
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>