canvas实现炫酷的黑客帝国数字雨特效

动机

最近重温黑客帝国,发现这个数字雨特效很炫酷,之前也看到网络上有相关类似的代码,我先自己思考了一种实现方式,最后参考网上给出的一种思路,最后写成了一个vue插件放在npm上,下面先上特效gif


是不是和电影里的很像,不过还是有点差距

自己的实现方法(失败)

对于这种较为复杂的动画特效,canvas是首选,当然css肯定也可以做,不过肯定超级复杂,代码量巨大。首先我第一眼看到这个特效,思路是这样的:
(1) 一般canvas用于绘制静态的图像,由于本例是动画效果,肯定得调用setTimeout或者setInterval或者raf,这里采用raf,不断绘制图像达到动态的效果,而且应当采用raf,它优于setTimeout/setInterval的地方在于它是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
(2) 绘制一个黑色的背景
(3) 由于数字雨看上去是独立的一条条的向下运动的数字字母序列,因此我需要新建一个DigitRain类,里面设置了该数字雨的各种属性,来控制该条数字雨的运动特性,代码见下面

    //数字雨类(参数是配置对象)
    function DigitRain(configObj){
        //数字雨的位置(x轴)
        this.digitRainXPos = configObj.digitRainXPos,
        //数字雨的位置(y轴)
        this.digitRainYPos = configObj.digitRainYPos,
        //数字雨的下落速度
        this.rainVelocity = configObj.rainVelocity,
        //数字雨的颜色
        this.rainColor = configObj.rainColor,
        //数字雨的拖尾长度
        this.rainTailLength = configObj.rainTailLength,
        //数字雨的文本内容
        this.rainText = configObj.rainText,
        ...
    }
复制代码

(4)然后写一个draw方法来控制其运动,最终在canvas里面调用fillText来画出文字

最终我写了一会发现困难太多,特别是文字拖尾效果的处理很麻烦,而且达不到效果,于是便作罢

换一种思路

参考了网上的一种思路,这种思路可谓是化繁为简,而且很容易理解,不得不佩服
(1) 同样是采用raf实现动画效果,首先根据canvas宽度和字体大小计算出雨滴下落的列数(宽度/字体大小),采用一个rainDropArray(长度是列数)记录下每个列的文字的y轴的位置,初始都为0,核心数据结构就是这个rainDropArray
(2) requestAnimationFrame的参数函数里,用for循环遍历rainDropArray,然后用fillText向canvas画上文字,x轴位置就是数组的index*字体大小,y轴位置就是rainDropArray[i]的值,而且每次fillText都用封装的random方法获取字符串的随机数字字母
(3)拖尾效果的处理:这里很巧妙,对于拖尾效果,只需要在requestAnimationFrame的参数函数里fillRect(0,0,.canvas.width,canvas.height)即可,而fillStyle设置为rgba(0,0,0,alpha),这样每次画图时都会画这么一个黑色背景,从而覆盖了之前画的字母,让字母颜色变淡,达到拖尾效果,通过控制alpha的值的大小来控制拖尾的长短,注意画图时没有用clearReact清除上次所画的内容,每次都是叠加上次所画的效果

如上图,虽然看着图中有很多字母,其实 requestAnimationFrame每次只画了红圈内的字母,也就是对应每列的字母,其余颜色变淡的字母都是 requestAnimationFrame以前画出来的,只不过被新画的黑色背景遮住了从而变暗,这样就完美的实现了拖尾效果 (4)最开始时 rainDropArray的每个值都是0,且所有列下落速度一样,因此动画刚开始是会是如下效果

整整齐齐的下落,因此需要在字母到达canvas底部时做处理,让其有先后顺序,代码如下,触底后给定一定概率让其的y轴位置重新置位0,从而达到该列循环下落的效果

 if(textYPostion>this.canvasHeight){
       if(Math.random()>0.9){
           this.rainDropPositionArray[i]=0;
       }
 }
复制代码

vue插件封装后的代码

总体代码量不多,不到150行,template部分就一个canvas






复制代码

github地址点这里

你可能感兴趣的:(canvas实现炫酷的黑客帝国数字雨特效)