今天和大家一起分享一下用 canvas 实现粒子动画效果的实现,就像下图的效果
要实现这样的效果,我们首先需要一段包含了 canvas 的基础 html 代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>粒子动画效果</title>
<meta name="Keywords" content="">
<meta name="Description" content="">
<style type="text/css">
html, body { width: 100%; height: 100%; padding: 0px; margin: 0px; }
canvas { display: block; margin: 0px auto; background: #363636; }
</style>
</head>
<body>
<canvas id="canvas" width="800" height="640"></canvas>
</body>
</html>
然后,我们需要在 canvas 上绘制粒子动画最终要呈现的文本内容
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = color;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '100px 微软雅黑';
ctx.fillText('玩具超人', canvas.width / 2, canvas.height / 2, 560);
接下来,我们需要把文字所包含的像素点转变为粒子数组,这里需要用到一个方法 getImageData
getImageData 方法,有四个参数 x / y / width / height,分别指定要获取图像数据的起始位置和尺寸,通过此方法,我们可以获取指定区域的图像数据,数据中保存了每个像素的 RGBA 信息。
for ( var y = 0; y < canvas.height; y++ ){
for ( var x = 0; x < canvas.width; x++ ){
var pixel = (x + (y * canvas.width)) * 4;
var sx = Math.floor(Math.random() * canvas.width);
var sy = Math.floor(Math.random() * canvas.height);
if ( r + g + b > 0){ // 仅当像素中包含色彩时才保存至粒子数组
particle.push({
sx: sx, // 起始 x 位置
sy: sy, // 起始 y 位置
cx: sx, // 当前 x 位置
cy: sy, // 当前 y 位置
ex: x, // 结束 x 位置,及这个像素在图片文本中的原始位置
ey: y, // 结束 y 位置,及这个像素在图片文本中的原始位置
td: Math.floor(Math.random() * frames),
tc: Math.floor(Math.random() * frames),
tt: 0,
r: bitmap.data[pixel + 0],
g: bitmap.data[pixel + 1],
b: bitmap.data[pixel + 2],
a: bitmap.data[pixel + 3]
});
}
}
}
有了粒子数组,剩下的就是动画的核心,我们要让每一个像素点,以动画形式从随机位置运动至原始位置。
具体的实现方法就是通过定时器,定时重绘图片,每一次重绘根据动画进行时间实时更新粒子位置。
for (var i = 0; i < particle.length; i++){
particle[i].tt ++;
particle[i].cx = particle[i].sx + (particle[i].ex - particle[i].cx) / 动画时长 * 当前时间;
particle[i].cy = particle[i].sy + (particle[i].ey - particle[i].cy) / 动画时长 * 当前时间;
}
现在我们就实现了一个基本的粒子动画效果,就像下图中的效果
上面虽然实现了我们要的效果,但是动画看起来比较生硬,不够自然。
这是因为我们的动画是匀速的,在现实中很少有运动是匀速的。
在动画中,为了模拟现实中的运动效果,会需要经常用到一个东西,贝塞尔曲线
贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。在Flash4中还没有完整的曲线工具,而在Flash5里面已经提供出贝塞尔曲线工具。
根据二次贝塞尔曲线的公式,我们来实现缓动动画函数:
function easing(s, e, t, d, p1, p2){
var p0 = 0;
var p3 = 1;
var tp = t / d;
var tn = 1 - t / d;
var p = p0 * Math.pow(tn, 3) + p1 * tp * Math.pow(tn, 2) * 3 + p2 * Math.pow(tp, 2) * tn * 3 + p3 * Math.pow(tp, 3);
return Math.floor(s + ( e - s ) * p);
}
现在我们就实现了如开头效果的动画
知道了实现的原理,我们再想做什么效果都会很轻松了,比如,只要我们把粒子起始位置指定图片底部中间,就可以实现下面的效果
// 全部从底部进入
sx = Math.floor(canvas.width / 2);
sy = canvas.height - 10;
或者如果我们指定粒子颗粒螺旋滚动,就可以实现这样的效果