菜鸟写Canvas动画

目录

前言

基础 - 概念

基础 - JS

实践

动画一: 运动的小球

动画二:灿烂的烟花

动画三:粒子文字


前言

        谜一般的动画,到底是怎么实现的呢?

基础 - 概念

动画三要素: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。

window.requestAnimationFrame - Web API 接口参考 | MDNwindow.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame

实践

  1. 先定义一个小球,小球的基本属性是:大小、颜色、速度、坐标点
        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;
        }
  2. 在页面中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();//颜色填充
        };
  3. 每次更新时去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;
            }

    这样我们就定义好一个基本的运动的小球;

  4. 那么,多个小球呢,是会发生碰撞的,如果不检测的话,就没有碰撞效果,显得僵硬了

    求两球之间的距离需要大于0,也就是两圆心之间的距离需要大于两个圆半径之合

    //求两圆心之间的距离
    let changeX = this.x - ball.x;
    let changeY = this.y - ball.y;
    let space = Math.sqrt(changeX*changeX + changeY*changeY);

  5. 随机生成小球

        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;
        }

  6. 调用 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(递增量,模拟重力加速度)。

  1. 单个光点的定义
    Fireworks(x, y, speed, color, size, angle) 
  2. 单个光点360度从四周散开:  angle = random(0, 2*Math.PI) 
  3. 速度的缩减递增:
    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。

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值