博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
奇妙的canvas:弹跳小球
阅读量:6587 次
发布时间:2019-06-24

本文共 2579 字,大约阅读时间需要 8 分钟。

前言

关于canvas的入门知识,网上有很多成熟的资料,我就不多做介绍啦。

弹跳小球算是一个比较常见的效果,接下来就讲讲如何在canvas里实现弹跳小球吧~

首先惯例先看效果图:

由于视频转码问题,可能有点稍卡,但是在浏览器里看是流畅的噢(。ì _ í。)

1.匀减速直线运动

为了方便理解之后的弹跳运动,我们先看看如何在canvas里实现匀减速直线运动。

我希望达到的目的是:给小球一个初速度,让小球以这个初速度做直线运动,刚好到达指定的位置时,停止运动。

(1)几个相关概念

requestAnimationFrame()

做过动画的人都知道,动画中经常会用到这个方法。它使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。回调的次数通常是每秒60次。类比于动画中的每一帧,每秒60帧,每一帧的时候,都要对canvas的画布进行擦除与重绘。

结合到匀减速运动,也就是说,我要知道每一帧,这个小球的坐标位置。

另外值得一提的是,canvas的坐标长介个样子:

几个物理概念

在这里,我把单位时间定为每一帧,单位距离定为每一个像素;

  • 速度v表示的是每单位时间内,移动的距离;

  • 加速度a表示每单位时间内,速度v的改变值;

我先指定这个小球只沿着x轴运动,运动距离是canvas的宽度,所以我们的问题是:

(1)如何让小球刚好在到达canvas边界时,速度递减到0?

​ 那就要求加速度a,由物理公式我们可以求出a=v^2/2s。

(2)在每一帧怎么更新小球位置?

​ 在每一帧都要更新速度v = v + a,和小球的x轴坐标x = x+v;

(2)代码片段

//匀减速小球;    function Ball(radius, x, y, v){        this.radius = radius;        this.x = x;        this.y = y;        this.v = v;        this.a = ((Math.pow(v,2)/(2*(canvas.width-x))))*(-1);    }    //绘制匀减速小球;    function drawBall(){        ctx.clearRect(0, 0, canvas.width, canvas.height);        ctx.fillStyle = '#fff';        ctx.beginPath();		//更新        ball.v += ball.a;        ball.x += ball.v;        ball.x = (ball.x + ball.radius > canvas.width) ? (canvas.width - ball.radius) : ball.x;        ctx.arc(ball.x, canvas.height/2, ball.radius, 0, 2 * Math.PI, true);        ctx.fill();        stop = ball.x + ball.radius >= canvas.width ? cancelAnimationFrame(stop) : requestAnimationFrame(drawBall);    }复制代码

2. 弹跳运动

我们知道,小球在重力的作用下,掉到地面,如果没有除去重力的其他外力作用,速度方向会变成相反,大小不变,但是由于产生形变和摩擦力等因素,对小球的速度造成一定损失,其速度方向变成相反,大小会比原来小,最后趋于0。

其实弹跳运动的实现也很简单,给他一个重力加速度,在它触碰到底部时,可以通过设置一个 -1~0的damping 值,让小球每次接触到底部时,v = v * damping,这样经过几个弹跳,v就会逐渐趋于0。

代码片段

//弹跳小球;    function BcBall(radius, x, y, v){        this.radius = radius;        this.x = x;        this.y = y;        this.v = v;        //设置重力加速度与损失比例        this.gravity = 0.5;        this.damping = -0.8;    } //绘制弹性小球;    var preV = 0;   //记录前一次速度    function drawBcBall() {        ctx.clearRect(0, 0, canvas.width, canvas.height);        ctx.fillStyle = '#fff';        ctx.beginPath();        ball.v += ball.gravity;        ball.y += ball.v;        preV = ball.v;        ctx.arc(canvas.width/2, ball.y, ball.radius, 0, 2 * Math.PI, true);        ctx.fill();        stop = requestAnimationFrame(drawBcBall);        if(ball.y + ball.radius >= canvas.height){            ball.y = canvas.height - ball.radius;            ball.v *= ball.damping;                        if(Math.abs(preV - ball.v) < 0.5){                cancelAnimationFrame(stop);            }        }    }复制代码

Last

完整的代码在我的GitHub里面,有兴趣者可以查阅~

GitHub连接:

撒花~

欢迎关注公众号:CSandCatti,集合英语和前端知识于一身的公众号平台~

转载地址:http://erhno.baihongyu.com/

你可能感兴趣的文章
使用jQuery实现一个类似GridView的编辑,更新,取消和删除的功能
查看>>
幸运的背后,总是靠自身的努力在支撑
查看>>
云计算面临安全挑战
查看>>
C# 线程手册 第三章 使用线程 Monitor.TryEnter()
查看>>
分享11个超棒的移动应用(mobile apps)开发解决方案
查看>>
mysql5.5.17源代码安装
查看>>
关于【cocos2dx-3.0beta-制作flappybird】教程在3.2project中出现找不到CCMenuItem.h的解决方法...
查看>>
7z格式、LZMA压缩算法和7-Zip详细介绍
查看>>
imx6 uboot splash image
查看>>
转:全栈工程师的知识栈列表
查看>>
C/C++获取文件大小
查看>>
深入理解Java内存模型(五)——锁
查看>>
Chalubo僵尸网络来袭 IOT设备或将受到DDoS攻击
查看>>
实用功能一手玩转!复合机操控面板一览
查看>>
乌鲁木齐大雾弥漫 局地能见度不足200米
查看>>
骚年,还在为歌荒发愁吗?python教你爬取网易云热门歌单
查看>>
如何实现百万TPS?详解JMQ4的存储设计
查看>>
Play! Framework 系列(一):初探 play 框架
查看>>
Shiro【授权、整合Spirng、Shiro过滤器】
查看>>
MarkDown语法
查看>>