34行JavaScript代码真的能搞定一个粒子动画系统吗?
在web网页开发中,像这种使用粒子动画作为网页背景的情形非常常见。如下图所示:
但是要实现它看起来貌似很复杂,我曾经看到过一个使用150行代码实现的一个粒子动画效果!本篇文章就是要来实现这样一个粒子动画效果,并不需要这么多代码,仅仅34行就可以了。当然,这个效果就是一个单纯的粒子动画效果,没有交互,没有矢量,没有加速度,但是完全够用了。
开始吧
开始之前,你需要一点基本的Canvas的知识。
首先来分析下,这个动画效果所涉及到的一些变量:
1、速度
2、透明度
3、粒子的尺寸
以及粒子撞击到视图边界后,往反的方向移动。
初始化设置
首先来建一个基本的骨架。
HTML
<canvas id=c></canvas>
CSS
canvas {
position: absolute;
top: 0px;
left: 0px;
}
JavaScript
(()=>{
let $ = c.getContext("2d"),
w = c.width = window.innerWidth,
h = c.height = window.innerHeight,
//predefines...
})()
上面的代码定义了一个立即执行方法,并且定义了一些基础的变量。w、h即canvas的宽和高等于浏览器可视窗口的宽和高。
let pi2 = Math.PI*2,
random = t=>Math.random()*t,
binRandom = t=>Math.random()<t;
这段代码主要是用来创建随机数用的,在后面将会用到它们。接下里就是在屏幕上绘制粒子:
function draw(){
$.fillStyle="#222";
$.fillRect(0,0,w,h);
requestAnimationFrame(draw);
}
draw(); //do not forget to call the function
这个方法主要是来定义绘制粒子的一些属性,比如颜色、宽高等。下面就一步一步来绘制粒子使粒子动起来。
先来看下粒子的一些属性:
1、尺寸
2、位置
3、运动速度
4、透明度
我们把粒子的这些属性全部定义在一个数组里面:
let arr = new Array(500 /* amount */).fill().map(p=>{
return {
p: {x: random(w), y: random(h) }, //position
v: { //velocity
x: binRandom(0.5)? random(1) : random(-1),
y: binRandom(0.5)? random(1) : random(-1)
},
s: random(1)+2, //size
o: random(1)+.3 //opacity
}
})
下面就来分析下上面的代码。
1、首先我们创建了一个空的数组。map()方法会遍历数组中的元素并且返回一些指定的值。当然,现在还不能执行这个方法,因为数组是空的。
2、fill()方法则是用于将一个固定值替换数组的元素。
4、粒子的位置position是根据屏幕的宽和高和已经定义好的random方法来计算的。
5、Velocity这个参数主要是用来当粒子撞向可视窗口边缘的时候,使它运动的更加自然而设置的。
6、Size粒子的尺寸也是随机分配的。
7、Opacity,使用透明度是为了使粒子有一个很好的区分。随机分配粒子的透明度的值在.3到1.3之间。
接下来使渲染绘制粒子。
function draw(){
//stuff
arr.forEach(p=>{
$.fillStyle="rgba(255,255,255,"+p.o+")";
$.beginPath();
$.arc(p.p.x, p.p.y, p.s, 0, pi2);
$.closePath();
$.fill();
})
}
这就不用多解释了,就是用canvas提供的基本的方法来绘制粒子。这里用到的颜色、透明度、位置等直接就是已经在数组中定义好的。
粒子绘制好了,还差最后一步,就是让粒子动起来。
arr.forEach(p=>{
p.p.x += p.v.x;
p.p.y += p.v.y;
if (p.p.x > w || p.p.x < 0) p.v.x *= -1;
if (p.p.y > h || p.p.y < 0) p.v.y *= -1;
//rendering stuff
}
上面的代码是用来检测粒子是否已经运动到了可视窗口的边界,如果是,则往反的方向运动。
到这里为止,只花了30行代码就实现了一个简单的粒子动画效果。
在codepen上,有很多非常聪明的程序员。比如在我上一篇教程中,我通过eventListener来监听窗口是否缩放,而Mark (@Blindman67)就建议可以用一行代码来代替原来使用eventListener才能达到的目的。
(h !== innerHeight || w!==innerWidth) && (w=c.width=innerWidth,h=c.height=innerHeight);
非常的巧妙,就这样仅仅只需要34行代码就完成了粒子动画效果。
本文主要是从Bouncing Particles are not complicated这篇文章整理而来,有删减,有疏漏或者理解不到位的地方,还请多多指教!