之前在石川县烟花大会的那篇文章中提到过使用js制作出烟花效果,那篇文章中是使用图片的切换来实现的。网速不够快的话效果会非常不给力。而在html5中,可以使用canvas可以进行绘图,所有的效果都不用下载,在客户端就可以实现,所以就不会受到网速的影响了。
那么,如何使用js制作动画呢?以前的话,可以使用setInterval这个函数去实现,现在又出现一个requestAnimationFrame,据说流畅性比setInterval好一些。
canvas的几个绘图的方法可以从这里查看。而requestAnimationFrame这个函数,因为不同的浏览器对象名称不一样,需要考虑一下浏览器兼容性的问题。下面的这段代码就可以保证大部分的浏览器的兼容,可以如果不兼容requestAnimationFrame的话就会选择setTimeout来实现同样的功能。
requestAnimationFrame = window.requestAnimationFrame
|| window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame || window.oRequestAnimationFrame
|| function(callback) {
setTimeout(callback, 1000 / 60);
};
有了canvas跟requestAnimationFrame,就可以轻松实现烟花效果了。下面是具体的算法问题。
首先,模拟一个自由落体运动。
//requestAnimationFrame
(function (w, r) {
w['r'+r] = w['r'+r] || w['webkitR'+r] || w['mozR'+r] || w['msR'+r] || w['oR'+r] ||
function(c){ w.setTimeout(c, 1000 / 60); };
})(window, 'equestAnimationFrame');
//获取canvas
var c=document.getElementById("myCanvas");
var cxt=c.getContext("2d");
//设置填充背景色为黑色
cxt.fillStyle="#000000";
//绘制canvas黑色背景
cxt.beginPath();
cxt.fillRect(0, 0, 200, 200);
cxt.fill();
//初始点坐标
var x = 0;
var y = 70;
//初始速度为5,与X轴正方向逆时针呈60度
var speed = 5;
var angle = Math.PI * (5/3);
//x轴 y轴的位移增量
var incre_x = Math.cos(angle) * speed;
var incre_y = Math.sin(angle) * speed;
//重力,因为每秒要绘制60帧,所以这个值的由来是 9.8/60
var gravity = 0.16;
(function animate(){
//计算移动后的坐标,y轴方向需要考虑重力,x轴方向没有加速度
incre_y = incre_y + gravity;
x += incre_x;
y += incre_y;
//超出画布范围就结束动画
if(x > 200 || y > 200){
try { window.parent.endAnimation(location.href); } catch (e) {};
return;
}
//开始绘制
cxt.fillStyle="#ffffff";
cxt.beginPath();
cxt.arc(x, y, 2, 0, Math.PI*2, true);
cxt.fill();
//继续播放下一帧
requestAnimationFrame(animate);
})();
接下来就是烟花效果的具体实现部分。烟花燃放一般分几个过程:
- 由下而上运动到顶端
- 闪烁着爆炸开来
- 光亮逐渐消失
由下而上运动的部分这里不做了。只实现从爆炸以后颗粒做自由落体到消失的部分。自由落体在上面已经实现了,但是上面是做出来一个运动轨迹,我们要做动画效果的话需要将前面绘制的擦除掉,实现的方法就是每一帧都绘制一遍画布,这样前面的内容就被遮住,新绘制的内容就会显示出来。但是,这里我没有完全擦除,而是逐渐擦除(比如每次叠加一个透明度20%的层,5次叠加以后就会擦除),这样做会出现一种逐渐消失的效果。
上面模拟了一个烟花颗粒的运动轨迹,但是烟花爆炸的时候有很多颗粒,而且速度方向不一样(这里速度大小的差异就忽略不计了),可以使用随机函数生成其余颗粒的初速度方向。实现烟花闪烁的效果,让邻接的两帧绘制不同的颜色的点就可以实现了。比如第一帧使用黄色,第二帧使用灰色,第三帧再恢复黄色。
光亮逐渐消失部分可以使用一个衰减参数。不仅可以模拟光亮从大变小的效果,在颗粒的移动过程中也可以使用,因为烟花的爆炸颗粒的速度受到的空气阻力的影响还是比较大的。