回顾圆周运动

HTML5 Canvas:运动和轨迹中介绍了 圆周运动 的实现原理,回顾其计算方式为:

// (centerX, centerY) : 中心点坐标
// radius:旋转半径
// angle:旋转的角度

x =  centerX + Math.sin(angle) * radius
y =  centerY + Math.cos(angle) * radius

上面的公式表示:我们有已知的 中心点 坐标,已知的 旋转半径 和旋转后的控制点相对于 x 轴夹角,也就是 旋转角度 。然后,基于 旋转半径 和不断变化的 旋转角度 来计算出旋转后的控制点坐标。

但,有时候...

通过上一片文章,我们知道了一个物体的平抛运动在 HTML5 Canvas 中的实现原理。想一想一朵烟花的“爆炸”,其效果好像多个烟花颗粒的平抛运动的合集。按照这个思路,让我们来尝试实现这个烟花效果。

由于要画出多个烟花颗粒,按常规的画法缺点太多,要管理每个烟花颗粒的运动,最好是将一颗烟花颗粒封装为一个 颗粒对象 ,就像是将一个产品的生产过程模块化,模块化后只需提供生产产品所需的材料就可以了。

首先,我将之前的平抛代码封装起来:

    function Particle() {
        this.x = 100, this.y = 60;
        this.g = 1;
        this.v = 2;
        this.angle = 30;

        this.update = function () {
            // 匀速直线运动
            var vx = Math.cos(this.angle) * this.v;
            this.x += vx;

            // 匀加速直线运动
            var vy = Math.sin(this.angle) * this.v + this.g;
            this.y += vy;
        }

        this.draw = function () {
            ctx.beginPath();
            ctx.arc(this.x, this.y, 2, 0, 2 * Math.PI);
            ctx.fillStyle = 'hsla(0, 100%, 50%, 1)';
            ctx.fill();
        }
    }

其中,烟花颗粒包含了基本的运动参数,还将烟花颗粒的绘制和运动封装为函数,但这些远远不够。

简谐运动

简谐运动是最基本也是最简单的一种机械振动。当某物体进行简谐运动时,物体所受的力跟位移成正比,并且力总是指向平衡位置。

简谐运动的实现可以通过正弦曲线实现,正弦曲线是一种来自数学三角函数中的正弦比例的曲线。它的形状就像完美的海上波浪般,以三角函数正弦比例改变而形成。

正弦曲线在 canvas 中的应用使得图形运动或变化的过程中变得顺滑,并且,不断增大的弧度在正弦曲线的特性中产生只在 -1 和 1 范围内的值,于是形成了天然的循环效果。

什么是三角函数?

三角函数是基本初等函数之一,是以角度(数学上最常用弧度制,下同)为自变量,角度对应任意角终边与单位圆交点坐标或其比值为因变量的函数。也可以等价地用与单位圆有关的各种线段的长度来定义。

在 HTML5 Canvas 的应用中,三角函数一般用于在画布中计算三角形未知长度的边和未知的角度。

常见的三角函数包括正弦函数、余弦函数和正切函数。Javasript API 提供了 Math 对象包含了这些计算方法。

// 返回一个数值的正弦值。
Math.sin(x)

// 返回一个数值的余弦值。
Math.cos(x)

// 返回一个数值的正切值。
Math.tan(x)

// 其中参数 x 是一个表示弧度的数值
// 还有一些常用的反三角函数

// 返回一个数值的反正弦值(以弧度为单位)。
Math.asin(x)

// 返回一个数值的反余弦值(以弧度为单位)。
Math.acos(x)

// 返回一个数值的反正切值(以弧度为单位)。
Math.atan(x)

// 返回从正 x 轴到点 (x,y) 与原点连线之间的偏移角度值,这是一个逆时针角度,以弧度为单位。
Math.atan2(y, x) 

动画的基本原理

动画是指由许多帧静止的画面,以一定的速度(如每秒16张)连续播放时,肉眼因视觉残象产生错觉,而误以为画面活动的作品。为了得到活动的画面,每个画面之间都会有细微的改变。而画面的制作方式,最常见的是手绘在纸张或赛璐珞片上。

而基于 HTML5 Canvas 的图形一旦绘制出来,它就是一直静止在那里。如果需要移动它,我们不得不对所有图形(包括之前的)进行重绘。也就是说,实现动画效果就是在画布上绘制图像后,清空画布,然后再绘制图像,再清空...即在动画未完成播放之前不断的重复这样的操作!