# 怎么实现随机粒子

在第 4 节中,我们分析了炫酷背景特效的通性都有哪些,经过这些分析,你是不是已经手痒痒,想要自己实现一番但又不知从何下手呢?

本节,我将带大家实现在炫酷网页背景特效中的一个最常见的效果:随机粒子。

# 随机粒子特效分析

如果只是一个纯色或者渐变的背景,肯定会显得有点单调,我们还需要在渐变的基础上加一点 “料”,而这些 “料”通常都是粒子特效。 那么“粒子特效” 都有什么特点呢?

  • 粒子
  • 规则图形
  • 随机
  • 数量多

粒子特效这些年还是比较流行的,好多地方都可以看出使用了粒子特效。那么粒子特效是什么呢?

百度百科中对粒子特效定义如下:

将无数的单个粒子组合使其呈现出固定形态,借由控制器,脚本来控制其整体或单个的运动,模拟出现真实的效果。

粒子特效

上面的例子是一种常见的粒子特效,使用若干粒子构成文字 “Hello World”,并且每一个粒子都在运动,和物理学的 “粒子” 概念类似。

粒子特效的首要特点是数量多,在物理学中,粒子是能够以自由状态存在的最小物质组成部分,所以粒子的第一个特点就是数量多。

粒子特效的第二个特点是运动,正是因为组成物体的粒子在不断运动,我们才能看到物体在不断运动。

粒子特效第三个特点是随机,排列有整齐排列之美,凌乱有凌乱之美,整齐排列的可以直接平铺背景实现,直接使用 img 图片就可以。

但是要想有随机效果使用 img 图片就不可以了,所以我们主要使用 Canvas 实现随机粒子效果。各项参数都是随机生成的。

背景渐变

这个例子已经引用好多遍了╥﹏╥...但是它真的是很有特点啊,炫酷特效的通性全部都占有 o(////▽////)q

在这个例子中,我们可以将背景上的小 “星星” 看成粒子。粒子的数量是可以自己设置的,位置是随机出现的,大小也是随机生成的,包括透明度也是随机的,这样基本上每一个粒子都是独一无二的。

然后给粒子设置阴影以营造发光的特效,粒子在不断地“动”,做上升运动。

为什么设置随机粒子特效会受欢迎呢?我们来分析一下。首先是我们生成的每一个粒子都是独一无二的,并且每一次刷新位置都是随机的。这种效果是使用其他方式绘制图形都实现不了的(使用 svg 也是可以的,但是本小册不对 svg 绘图做过多的介绍ヘ(;´Д`ヘ))。

# 实现随机粒子特效

现在我们来一起实现一个随机粒子特效。

效果如下:

随机粒子特效

# 创建全屏 Canvas

首先,我们需要一个全屏的 Canvas 画布。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        html,body {
            margin:0;
            overflow:hidden;
            width:100%;
            height:100%;
            cursor:none;
            background:black;
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>

<script>
    var ctx = document.getElementById('canvas'),
        content = ctx.getContext('2d'),
        WIDTH,
        HEIGHT;

    WIDTH = document.documentElement.clientWidth;
    HEIGHT = document.documentElement.clientHeight;

    ctx.width = WIDTH;
    ctx.height = HEIGHT;

</script>
</body>
</html>

我们使用 WIDTHHEIGHT 两个常量储存屏幕宽度和高度信息,我们习惯使用大写来表示改变量为常量,不可变,将屏幕宽度和高度信息储存在常量中是因为我们在稍后还会用到。

这时,你应该得到一个全屏的并且为黑色的 Canvas。

# 设置 Round_item

在创建了一个全屏的 Canvas 之后,我们来创建单个的 Round_item 类。

首先我们 Round_item 类需要有什么参数呢?我们要设置的是位置随机、透明度随机、半径随机的圆。为了区分不同的圆,我们还应该设置一个唯一的 index 参数。

所以我们需要的参数有:

  • x 坐标
  • y 坐标
  • 半径
  • 透明度
  • index

根据上面这些可以得出我们的 Round_item 类:

    function Round_item(index,x,y) {
        this.index = index;
        this.x = x;
        this.y = y;
        this.r = Math.random() * 2 + 1;
        var alpha = (Math.floor(Math.random() * 10) + 1) / 10 / 2;
        this.color = "rgba(255,255,255," + alpha + ")";
    }

这里我们使用了构造函数的方式来创建单个的圆,我们还需要一个变量 initRoundPopulation 来设置 round 的个数,然后我们便可以通过 for 循环创建出 initRoundPopulation 个圆。

# 设置 draw() 方法

在设置了单个的 Round_item 类之后,我们还要给每一个 round 设置 draw() 方法,所以我们需要将 draw() 方法设置在 Round_item 的原型中,这样我们创建出来的每一个 Round_item 实例对象都拥有了 draw() 方法。

draw() 方法的内容就是我们第 3 节讲到的画圆的方式,这里也就不再过多的说明了,忘记的快去第 3 节补习补习ヽ(;´Д`)ノ

    Round_item.prototype.draw = function () {
        content.fillStyle = this.color;
        content.shadowBlur = this.r * 2;
        content.beginPath();
        content.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
        content.closePath();
        content.fill();
    };

# 设置初始化 init() 函数

然后我们就需要设置初始化 init() 函数了,在 init() 函数中,我们的主要任务是创建单个的 round,然后使用其 draw() 方法。

    function init() {
        for(var i = 0; i < initRoundPopulation; i++ ){
            round[i] = new Round_item(i,Math.random() * WIDTH,Math.random() * HEIGHT);
            round[i].draw();
        }

    }

至此,我们已经完成了随机粒子的实现,完整的代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        html,body {
            margin:0;
            overflow:hidden;
            width:100%;
            height:100%;
            cursor:none;
            background:black;
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>

<script>
    var ctx = document.getElementById('canvas'),
        content = ctx.getContext('2d'),
        round = [],
        WIDTH,
        HEIGHT,
        initRoundPopulation = 80;


    WIDTH = document.documentElement.clientWidth;
    HEIGHT = document.documentElement.clientHeight;

    ctx.width = WIDTH;
    ctx.height = HEIGHT;

    function Round_item(index,x,y) {
        this.index = index;
        this.x = x;
        this.y = y;
        this.r = Math.random() * 2 + 1;
        var alpha = (Math.floor(Math.random() * 10) + 1) / 10 / 2;
        this.color = "rgba(255,255,255," + alpha + ")";
    }

    Round_item.prototype.draw = function () {
        content.fillStyle = this.color;
        content.shadowBlur = this.r * 2;
        content.beginPath();
        content.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
        content.closePath();
        content.fill();
    };

    function init() {
        for(var i = 0; i < initRoundPopulation; i++ ){
            round[i] = new Round_item(i,Math.random() * WIDTH,Math.random() * HEIGHT);
            round[i].draw();
        }

    }

    init();
</script>
</body>
</html>

随意写的代码,欢迎大家 review~