上图:

前面有用Java写过一个粒子爆炸烟花效果,和这个思路是一样的,不过是Android程序,有兴趣的可以看看:
Android 粒子爆炸 烟花效果。
现在这个是用Html Canvas + Js写的。
重点记录:
1.Html Canvas中不存在 Invalidate, 所以想要界面重新渲染,必须手动调用canvas.clearRect(0, 0, cn.width, cn.height);清除画布再重新绘制。
2.Js ES6以前没有Class类,所以得使用function的方式实例化类。
3.在Android中我们调用Invalidate来刷新Canvas,让程序陷入递归,不停的绘制,不停得刷新, 但在Js中我发现使用递归刷新的方式不得行,所以改用定时器setInterval的方式,每30毫秒重绘一次画布。
注意点就这些,下面就是实现了, 先看看单个气球的草图:

可以看到,单个气球由三部分构成:
1.气球头。
2.气球中间扭动线。
3.气球尾部摆动线。
开始,当然是面向对象编程啦:
先给他定义这三个类出来:
//气球实体 centerX:圆心x centerY:圆心y raduis:半径 color:颜色 speed:运动速度 line:贝塞尔曲线 tailLine:尾部直线
function Cirecle(centerX, centerY, raduis, color, speed, line, tailLine) {
this.centerX = centerX;
this.centerY = centerY;
this.raduis = raduis;
this.color = color;
this.speed = speed;
this.line = line;
this.tailLine = tailLine;
}
//贝塞尔曲线实体
function Line(lineOnePointX, lineOnePointY, lineTwoPointX, lineTwoPointY, lineEndPointX, lineEndPointY, onePointLeftMove, twoPointLeftMove, onePointSpeed, twoPointSpeed) {
this.lineOnePointX = lineOnePointX;
this.lineOnePointY = lineOnePointY;
this.lineTwoPointX = lineTwoPointX;
this.lineTwoPointY = lineTwoPointY;
this.lineEndPointX = lineEndPointX;
this.lineEndPointY = lineEndPointY;
this.onePointLeftMove = onePointLeftMove;
this.twoPointLeftMove = twoPointLeftMove;
this.onePointSpeed = onePointSpeed;
this.twoPointSpeed = twoPointSpeed;
}
//尾线实体
function TailLine(startX, startY, endX, endY){
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
}
因为写的时候思维带入到粒子爆炸去了,所以头部和气球这个整体放在一个类了,其实应该把头部单独拉出一个新类的。
有了这些实体,下面就可以将他们实例化然后绘制到Cnavas上了:
1.html中定义画布:
<body>
<canvas id="canvas" width="800px" height="500px"></canvas>
</body>
2.Js中获取画布:
var cn = document.getElementById("canvas");
var canvas = cn.getContext("2d");
3.鼠标点击时生成气球:
cn.onclick = function (e) {
var centerX = e.offsetX;
var centerY = e.offsetY;
var color = getRandomColor();
var speed = Math.floor(Math.random() * 2 + 1);
var onePointSpeed = 4;
var twoPointSpeed = 4;
console.log(onePointSpeed);
console.log(twoPointSpeed);
var line = new Line(centerX - raduis, centerY + raduis * 2, centerX + raduis, centerY + raduis * 3, centerX, centerY + raduis * 4, false, false, onePointSpeed, twoPointSpeed);
var tailLine = new TailLine(line.lineEndPointX, line.lineEndPointY, line.lineOnePointX, centerY + raduis * 4.5);
var circle = new Cirecle(centerX, centerY, raduis, color, speed, line, tailLine);
circlrs.push(circle);
drawCircle();
}
ok, 到这里我们每次点击鼠标的时候就会生成一个气球,然后存在我们的circlrs里了,下面就只要把circlrs里的气球绘制在Canvas上面就好了。
4.气球的绘制:
//画一个实心圆
canvas.beginPath();
canvas.shadowBlur = 20;
canvas.shadowOffsetX = 10100;
canvas.shadowOffsetY = 10100;
canvas.fillStyle = circle.color;//填充颜色,默认是黑色
canvas.arc(circle.centerX, circle.centerY, circle.raduis, 0, Math.PI * 2, false);
canvas.fill();//画实心圆
canvas.strokeStyle = circle.color;//填充颜色,默认是黑色
canvas.moveTo(circle.centerX, circle.centerY + circle.raduis);
canvas.bezierCurveTo(line.lineOnePointX, line.lineOnePointY, line.lineTwoPointX, line.lineTwoPointY, line.lineEndPointX, line.lineEndPointY)
canvas.stroke();
canvas.moveTo(tailLine.startX, tailLine.startY);
canvas.lineTo(tailLine.endX, tailLine.endY);
canvas.stroke();
circle.centerY -= circle.speed;
//贝塞尔
line.lineOnePointY = circle.centerY + raduis * 2;
line.lineTwoPointY = circle.centerY + raduis * 3;
line.lineEndPointY = circle.centerY + raduis * 4;
//尾线
tailLine.startX = line.lineEndPointX;
tailLine.startY = line.lineEndPointY;
tailLine.endX = line.lineOnePointX;
tailLine.endY = circle.centerY + raduis * 4.5;
这里分成了三部分,头,身,尾,
身部贝塞尔曲线的起点在圆的正下方,外加两个控制点形成S型,尾部直线起点在贝塞尔曲线的终点。
5.接着设置定时器让气球动起来:
interval = setInterval(function () {
//绘制代码
}, 30)
每30毫秒刷新一次Canvas, 动起来的原因是,我们每次刷新画布时,都会动态更新三个部位的属性,所以刷新后他们的绘制位置就会发生该改变,这里面也是写得比较死了,好像不是相对一个点,还有待优化。。。。。
**值得注意的是,在每个气球飞出画面之后,要将气球清除,并在所有气球都游出画面后,停止定时器,直到重新有气球生成时再打开定时器,以防止不必要的内存开销。
下面是源码,see see:
https://github.com/amggg/JsParticalDemo/tree/master
网友评论