目录
前言
谜一般的动画,到底是怎么实现的呢?
基础 - 概念
动画三要素:item、path、speed
- Item:待运动的单位
运动的个体,可能是一个圆、一个点、多边形,不规则图形等,从每一帧中寻找变化的个体,可能是多个,也可能是单个。
- Path:路径
简单的路径一般有:直线、圆【椭圆】、贝塞尔曲线
直线:X轴和Y轴上的运动速度是恒定的。
即:已知
x=x+vx;
y=y+vy;
vx、vy是一个常量,恒定的。
圆:绕圆来运动的话,一般X轴和Y轴上的运动速度用的是动态的选用三角函数来表示。
vx = speed*Math.cos(angle);
vy= speed*Math.sin(angle);
贝塞尔曲线:
这部分内容三言两语不好说明,推荐几篇文章查阅:
必须要理解掌握的贝塞尔曲线https://www.jianshu.com/p/0c9b4b681724
- Speed:速度
一般情况是直接定义 vx (x轴速度),和 vy(y轴速度);
但是也可以 定义一个speed 和 angle
vx = Spend * Math.cos(Angle)
vy = Spend * Math.sin(Angle)
基础 - JS
- Canvas
(1)我们的绘制操作主要是通过 CanvasRenderingContext2D 对象来的,下面我们都简写为ctx。ctx的获取 就是 canvas.getContext('2d'),如下
var ctx = canvas.getContext('2d');
(2)canvas的坐标轴方向
(3)常用的一些绘制方法,上w3school的截图:
- requestAnimationFrame
requestAnimationFrame:用来执行我们的动画。每次浏览器重绘都会去调用这个方法。浏览器刷新频率一般是60Hz,16.6ms。
实践
-
动画一:运动的小球
- 先定义一个小球,小球的基本属性是:大小、颜色、速度、坐标点
function Ball(x, y, vx, vy, color, width) { this.x = x; //x轴坐标 this.y = y; //y轴坐标 this.vx = vx; //x轴向速度 this.vy = vy; //y轴向速度 this.color = color; this.width = width; }
- 在页面中draw出来
Ball.prototype.draw = function () { ctx.beginPath();//开始画布 ctx.fillStyle = this.color;//定义填充的颜色 ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);//画一个圆 ctx.fill();//颜色填充 };
- 每次更新时去update基本数据
Ball.prototype.update = function () { //碰到墙壁回弹 if (this.x + this.width > XMAX || this.x - this.width < 0) { this.vx = -this.vx; } if (this.y + this.width > YMAX || this.y - this.width < 0) { this.vy = -this.vy; } //根据速度前进 this.x = this.x + this.vx; this.y = this.y + this.vy; }
这样我们就定义好一个基本的运动的小球;
-
那么,多个小球呢,是会发生碰撞的,如果不检测的话,就没有碰撞效果,显得僵硬了
求两球之间的距离需要大于0,也就是两圆心之间的距离需要大于两个圆半径之合
//求两圆心之间的距离 let changeX = this.x - ball.x; let changeY = this.y - ball.y; let space = Math.sqrt(changeX*changeX + changeY*changeY);
-
随机生成小球
function createBall() { //Ball(x, y, vx, vy, color, width) let ball = new Ball( random(0, XMAX), random(0, YMAX), random(-VMAX, VMAX), random(-VMAX, VMAX), 'rgba('+ random(1,255)+',' + random(1, 255)+',' + random(1, 255)+',' + 1 + ')', random(WIDTH_MIN, WIDTH_MAX) ) return ball; }
-
调用 requestAnimationFrame 来更新小球
var balls = []; function loop() { ctx.fillStyle = '#000'; ctx.fillRect(0 , 0 , XMAX, YMAX); if (balls.length < BALLCOUNT) { for(let i = BALLCOUNT; i>= balls.length;i--) { balls.push(createBall()) } } balls.forEach(function (ball) { ball.update(); ball.draw(); ball.checkCollide(); }) requestAnimationFrame(loop) } loop();
-
动画二:灿烂的烟花
首先,我们要先找到有个绘画的主体Item:单个烟花;
然后,观察一下路线:单个烟花从下往上到达某一点之后绽放出来,就变成一个个小小的光点;
最后,观察这些光点,是360度从四周散开的,但是慢慢的扩散开的速度下降,却一直防下垂。可得出 vx * WEAKEN(缩减量), vy + STENGTHEN(递增量,模拟重力加速度)。
- 单个光点的定义
Fireworks(x, y, speed, color, size, angle)
- 单个光点360度从四周散开: angle = random(0, 2*Math.PI)
- 速度的缩减递增:
this.vx = this.vx * WEAKEN; // x轴的速度缩减 this.vy = this.vy * WEAKEN + STENGTHEN; // y轴的速度递增【模拟重力加速度】 this.size = this.size * WEAKEN_SIZE; // 尺寸大小也在缩减
-
动画三:粒子文字
实现要点:
1. 虚拟一个canvas在上面写上文字,文字颜色和底色差距很大,最好一个白,一个黑;
2.计算出文字在canvas上面的坐标;
(1)根据 ctx.getImageData(0, 0, width, height) 得出当前的imageData;
(2)遍历imageData,如果当前的像素值的色值和其他不一致,就可得出是文字的占位。
3.使用得出的坐标列表,用小球来填充在我们的主canvas。