记录13 画布动画

用 JavaScript 创建画布动画,是创建一个定格图案,擦除该图案, 然后在一个新的位置重新绘制它。这听上去有很多个步骤,但是, JavaScript 可以很快地更新图形的位置,以创建一个平滑的动画。

我们使用画布和 setInterval 来绘制一个方块,并且让其缓慢地在页面上移动

  • 调用了 clearRect,它在画布上清除出一个矩形区域。
    因为方块移动范围是在画布里面,所以我们清除的区域是200*200,这样无论方块此时移动到哪里都会被清除。

  • 间隔为30毫秒,在(0,0)处画一个2020的方块,然后清除区域内容;在(1,0)处画一个2020的方块,然后清除区域内容;然后在(2,0)处画。。。。,因为过程很平滑,所以看起来就像看动画一样。超出画布范围后回到左侧重新开始移动。

<body>
    <canvas id="canvas" width="200" height="200"></canvas>>
    <script type="text/javascript" src="jquery-3.1.1.js"></script>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        var position = 0;
        setInterval(function(){
            ctx.clearRect(0,0,200,200);
            ctx.fillRect(position,0,20,20);
            position++;
            if(position > 200){
                position = 0;
            }
        },30);
    </script>
</body>

注意ctx.fillRect(position,0,20,20);必须放在后面,不然每次都是一执行绘制方法马上执行清除方法,页面始终空白。而先清除,再绘制之后,间隔30毫秒才开始继续清除、绘制,这样才能达到动画效果。

方块大小变化的动画

<body>
    <canvas id="canvas" width="200" height="200"></canvas>
    <script type="text/javascript" src="jquery-3.1.1.js"></script>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        var size = 0;
        setInterval(function(){
            ctx.clearRect(0,0,200,200);
            ctx.fillRect(0,0,size,size);
            size++;
            if(size > 200){
                size = 0;
            }
        },30);
    </script>
</body>

绘制一个在页面上乱飞的蜜蜂

1,绘制蜜蜂可以构造多个圆形的组合图形
2,乱飞就是让这个组合图形随机移动

  • 定义一个circle方法,根据参数 fillCircle 来绘制实心圆或者圆形边框。
  • drawBee方法用于调用circle方法绘制出蜜蜂
  • 创建一个update方法来随机修改米饭的x坐标和y坐标,使得蜜蜂实现在画布上随机移动

1,offset 值会给出一个在-2 到 2 之间的随机值,这是蜜蜂每次随机移动的距离大小。
2,通过确保coordinate 不会增加到200 以上或者减少 到 0 以下,从而防止蜜蜂离开画布。如果coordinate 大于200,将其设置回 200;如果 coordinate 小于 0,将其设置回 0。

  • 返回了新的coordinate 值,也就是新的坐标。传入x坐标会返回新的x坐标,传入y的坐标会返回新的y坐标(分别传入是因为x方向移动距离不一定等于y方向的移动距离,体现随机的不只是移动方向还有移动距离)

coordinate += offset; 的+和=之间不允许有空格,不然报错one.html:48 Uncaught SyntaxError: Unexpected token =

完整代码如下:

<body>
    <canvas id="canvas" width="200" height="200"></canvas>
    <script type="text/javascript" src="jquery-3.1.1.js"></script>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");

        //蜜蜂起始位置
        var x= 100;
        var y= 100;

        var circle = function(x,y,radius,fillCircle){
            ctx.beginPath();
            ctx.arc(x,y,radius,0,Math.PI*2,false);
            if(fillCircle){
                ctx.fill();  //画出实心圆
            }else{
                ctx.stroke();  //画出圆形边框
            }
        };

        //绘制蜜蜂
        var drawBee = function(x,y){
            ctx.lineWidth = 2;
            ctx.strokeStyle = "Black";
            ctx.fillStyle = "Gold";

            //调用上面的circle函数,最后一个参数对应上面定义的fillCircle参数
            //第一个圆是实心圆,代表蜜蜂身体
            circle(x,y,8,true);
            //在蜜蜂身体绘制一个黑色的圆边框
            circle(x,y,8,false);
            //在身体上绘制黑色边框的翅膀
            circle(x-5,y-11,5,false); 
            circle(x+5,y-11,5,false);
            //在最上方绘制两个眼睛
            circle(x-2,y-1,2,false);
            circle(x+2,y-1,2,false);
        }

        var update = function(coordinate) {
            var offset = Math.random()*4 - 2;
            // coordinate + = offset; 错误
            coordinate += offset; 
            if(coordinate > 200){
                coordinate = 200;
            }
            if(coordinate < 0){
                coordinate = 0;
            }
            return coordinate;
        };

        setInterval(function(){
            ctx.clearRect(0,0,200,200);
            drawBee(x,y);
            x=update(x);
            y=update(y);
            ctx.strokeRect(0,0,200,200);
        },30);

    </script>
</body>

效果图如下:


Paste_Image.png

弹跳的球(带有速度和方向)

现在,我们来制作在画布上弹跳的球。无论何时,当球碰到墙的时候, 它都会以一个角度弹回,就像是一个橡皮球一样

开始位置设置在(100,100),this.xSpeed设置为-2将会在动画的每一步中将球向左移动2个像素。 this.ySpeed设置为3使得球在每一个动画步骤中向下移动3个像素。因此, 在每一帧之间,球将会斜着向下移动(3 个像素)并向左移动(2 个像素)。


Paste_Image.png
  • 向Ball原型添加draw方法绘制球,以便Ball构造方法创建的任何实例都能够使用它

  • 弹跳球,我们检查球是否碰到一面墙。如果是,通过将xSpeed属性或ySpeed 属性取反(将其与-1 相乘)而更新它们。例如,如果球碰到了底部的墙,将this.ySpeed取反。因此,如果this.ySpeed是3,取反后将其变为-3。如果 this.ySpeed是-3,取反后将其设置为3。


完整代码如下:

<body>
    <canvas id="canvas" width="200" height="200"></canvas>
    <script type="text/javascript" src="jquery-3.1.1.js"></script>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");

        //球的属性,包括位置坐标和速度
        var Ball = function(){
            this.x=100;
            this.y=100;
            this.xSpeed = -2;
            this.ySpeed = 3;
        }

        //向Ball原型添加draw方法绘制球,以便Ball构造方法创建的任何实例都能够使用它
        var circle = function (x,y,radius,fillCircle){
            ctx.beginPath();
            ctx.arc(x,y,radius,0,Math.PI*2,false);
            if(fillCircle){
                ctx.fill();
            }else{
                ctx.stroke();
            }
        };
        Ball.prototype.draw = function(){
            circle(this.x,this.y,3,true);
        };

        //移动球,就是根据速度改变球的坐标属性值
        Ball.prototype.move = function(){
            this.x += this.xSpeed;
            this.y += this.ySpeed;
        };

        //检查球是否会与墙碰撞,如果球移动到画布边界,
        //水平到达边界,让x方向速速度取反
        //竖直达到边界,让y方向速度取反
        Ball.prototype.checkCollision = function() {
            if(this.x < 0 || this.x > 200 ){
                this.xSpeed = -this.xSpeed;
            }
            if(this.y < 0 || this.y > 200 ){
                this.ySpeed = -this.ySpeed;
            }
        }

        //实现球的动画
        var ball = new Ball();
        setInterval(function(){
            //清除画布
            ctx.clearRect(0,0,200,200);
            //绘制球体,与上面清除画布的间歇性配合平滑檫除重新绘制,达到动画效果
            ball.draw();
            ball.move();
            ball.checkCollision();
            //绘制墙,就是边框,与clearRect没有任何关系
            ctx.strokeRect(0,0,200,200);
        },30);

    </script>
</body>

效果图如下

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容