一、为什么要写这篇文章

某年某月某时某种原因,我在慕课网上看到了一个大神实现了关于小球的抛物线运动的代码,心中很是欣喜,故而写这篇文章来向这位大神致敬,同时也为了弥补自己在运动效果和动画效果制作方面的不足

二、几种简单的直线运动

这一部分主要讲解的是简单的运动效果的实现原理,其实所有的canvas动画效果的实现在核心思想是一致的:都是先定义个初始的状态,然后定义一个定时器,定时器内执行一个方法,记得在这个方法中要对当前的画面清除,然后在这个方法中重新绘制需要变化的效果,由于人眼存在残影,所以短时间内的中断的变化可以看成是连续的变化,这个就是canva动画运动原理

最简单的要从匀速直线运动说起,然后是匀加速直线运动。

匀速直线运动

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas匀速直线运动</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id="canvas">你的浏览器不支持canvas,请跟换其他浏览器试一试</canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>

JS代码

window.onload=function(){
var canvas=document.getElementById('canvas');
canvas.height=728;
canvas.width=1024;
var context=canvas.getContext('2d');
context.fillStyle='red';
context.beginPath();
context.arc(800,300,30,0,2*Math.PI,true);
context.closePath();
context.fill();
setInterval(function(){
run(context);
}, 50);
};
var speed=0;
var startPoint=800;
function run(cxt){
speed=-7;
cxt.clearRect(0,0,1024,728);
//cxt.top+=speed;
startPoint+=speed;
cxt.beginPath();
cxt.arc(startPoint,300,30,0,2*Math.PI,true);
cxt.closePath();
cxt.fill();
}

运行效果如下:

PS:这里面画面有点卡顿,是录制的时候软件的因素造成的,直接运行上诉代码是可以看到正常运行的效果

重点代码分析:

var speed=0;
var startPoint=800;
function run(cxt){
speed=-7;
cxt.clearRect(0,0,1024,728);
//cxt.top+=speed;
startPoint+=speed;
cxt.beginPath();
cxt.arc(startPoint,300,30,0,2*Math.PI,true);
cxt.closePath();
cxt.fill();
}

先把速度定义为0和获取开始点,然后将canvas画面的内容清除,接着是计算变化后的坐标,然后进行重绘(坐标重新计算是运动关键所在)

匀变速直线运动

匀变速直线运动的定义:在直线运动中,把加速度的大小和方向都不改变的运动(加速度为正时),称之为匀加速直线运动。

基本公式:

速度公式: V=V0+at
位移公式: x=V0t+1/2at^2

所以我们依次需要定义这样的几个变量加速度a,初始速度V0,位移量x,随时间变化的速度v,时间time,这几个变量的初始化值均为0,代码如下所示:

HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas匀加速直线运动</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id="canvas">你的浏览器不支持canvas,请跟换其他浏览器试一试</canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>

JavaScript代码:

window.onload=function(){
var canvas=document.getElementById('canvas');
canvas.height=728;
canvas.width=1024;
var context=canvas.getContext('2d');
context.fillStyle='red';
context.beginPath();
context.arc(800,300,30,0,2*Math.PI,true);
context.closePath();
context.fill();
setInterval(function(){
run(context);
}, 50);
};
var v0=0;//初始速度
var a=0;//加速度
var v=0;//变化的速度
var time=0;//时间
var x=0;//位移量
var startPoint=800;//起始点
// V=V0+at
// x=v0t+1/2at^2
// v^2-V^2=2ax
function run(cxt){
time+=0.05;
a=10;
x=-(0.5*a*(time*time));//位移公式代入
startPoint+=x;
cxt.clearRect(0,0,1024,728);
cxt.beginPath();
cxt.arc(startPoint,300,30,0,2*Math.PI,true);
cxt.closePath();
cxt.fill();
}

运行的效果如下:

基本上直线运动比较典型的也就是这两种,如有遗漏其他运动或者是需要博主讲解其他运动的制作的,请在留言板上留言

三、简单的曲线运动的实现

说到简单的曲线运动,我们就从最简单的也是我认为最基础的运动圆周运动说起

1、匀速圆周运动

圆周运动的定义:质点沿圆周运动,如果在任意相等的时间里通过的圆弧长度都相等,这种运动就叫做“匀速圆周运动”,亦称“匀速率圆周运动”。因为物体作圆周运动时速率不变,但速度方向随时发生变化。所以匀速圆周运动的线速度是每时每刻都在发生变化的。

匀速圆周运动的实现与分析

匀速圆周运动的实现第一反应我们会选择通过匀速圆周运动的物理公式进行计算得到,但是物理公式中没有哪条明确的公式是可以把单位时间的变化量和所在点的具体坐标相关联的,显然这样的一条思路是行不通的,从物理公式上面是来说是不具有可行性的,所以我们应该要换另外的一种方法来实现,这个时候我们应该要看透匀速圆周运动的本质,本质上来说,匀速圆周运动的实现其实就是通过一个原点,然后在这个原点的基础之上对一个物体进行360度的旋转。好的,相信对canvas api熟悉的小伙伴已经想到了,是的,我们可以通过旋转或者是矩阵来实现

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas实现圆周运动</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id="canvas">你的浏览器不支持canvas,请跟换其他浏览器试一试</canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>

相关的JavaScript代码:

window.onload=function(){
var canvas=document.getElementById('canvas');
canvas.height=728;
canvas.width=1024;
var context=canvas.getContext('2d');
drawNotChange(context);
context.fillStyle='blue';
context.beginPath();
context.arc(500,550,30,0,2*Math.PI,true);
context.closePath();
context.fill();
setInterval(function(){
run(context);
}, 50);
};
var time=0;//定义运动的执行次数
function run(cxt){ cxt.clearRect(0,0,1024,728);
drawNotChange(cxt);
cxt.save();//将当前以左上角坐标为(0,0)的上下文环境进行保存,这样是为了在接下来中要进行画布偏移后,可以进行还原当前的环境
cxt.translate(500,400);
cxt.rotate(time*8*Math.PI/180);//设定每次旋转的度数
cxt.fillStyle='blue';
cxt.beginPath();
cxt.arc(0,150,30,0,2*Math.PI,false);
cxt.closePath();
cxt.fill();
cxt.restore();//将当前为(500,400)的点还原为(0,0),其实在save中就是将上下文环境保存到栈中,在restore下面对其进行还原
time+=1;
} //绘制不变因素
function drawNotChange(context){
context.fillStyle='red';
context.beginPath();
context.arc(500,400,30,0,2*Math.PI,true);
context.closePath();
context.fill();
context.beginPath();
context.arc(500,400,150,0,2*Math.PI,true);
context.closePath();
context.stroke();
}

运行的结果如下:

为了让读者能够明白其中的原理,我会在注释中尽量将代码注释清楚

2、椭圆运动

可能有些小伙伴们对于高中的知识都已经遗忘了,但是这个不妨碍,因为在接下来我们会通过一步一步的复习相关数学知识最后才来实现效果,但是如果对高中知识比较熟悉的小伙伴,建议跳过这个阶段,直接看代码就行了,以免浪费时间

椭圆的定义:椭圆(Ellipse)是平面内到定点F1、F2的距离之和等于常数(大于|F1F2|)的动点P的轨迹,F1、F2称为椭圆的两个焦点。其数学表表达式为:|PF1|+|PF2|=2a(2a>|F1F2|)

椭圆图解:

长轴长我们用2a表示,短轴长我们用2b表示

假设椭圆的长轴与X轴平行,那么表达式如下所示:

根据三角函数之间的关系我们可以推导出:

x=a+cos(t)

y=b+sin(t)

这里面的t代表的是单位是单位时间内旋转的弧度

具体的推导会在以后有时间,为大家专门写一篇博文来讲解一些公式的推导过程

关于椭圆的数学知识已经讲完了,还是不太清楚的同学请执行去复习高中的知识,在这里就不再累赘了。

我们还开始代码实现之前还有先假设好一些参数,我们假设原点O(500,300),绕椭圆运动的物体为圆形半径为30,其中长半轴长a=200,短半轴长为b=100,每次重新获取物体的运动后的移动位置的时候,x都会变化一个单位,旋转为顺时针旋转,开始位置为原点的正左边的端点,最后原点我们以一个黑色且半径为10的小球表示。注意:上述的数据可以读者自行定义,但是要注意这个前提是必须保证a>b,如果a<b那么就不是这个公式了

我们先来实现椭圆的轨迹效果:

HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas实现椭圆运动</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<canvas id="canvas">你的浏览器不支持canvas,请跟换其他浏览器试一试</canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>

JavaScript代码:

var a=200,
b=100,
radius=30;
window.onload=function(){
var canvas=document.getElementById('canvas');
canvas.height=668;
canvas.width=1024;
var cxt=canvas.getContext('2d');
cxt.beginPath();
cxt.arc(300,300,10,0,2*Math.PI,true)
cxt.closePath();
cxt.fill();
route(cxt,300,300,200,100);
}; //椭圆路线绘制
function route(context,x,y,a,b){
//max是等于1除以长轴值a和b中的较大者
//i每次循环增加1/max,表示度数的增加
//这样可以使得每次循环所绘制的路径(弧线)接近1像素
var step = (a > b) ? 1 / a : 1 / b;
context.beginPath();
context.moveTo(x + a, y); //从椭圆的左端点开始绘制
for (var i = 0; i < 2 * Math.PI; i += step)
{
//参数方程为x = a * cos(i), y = b * sin(i),
//参数为i,表示度数(弧度)
context.lineTo(x + a * Math.cos(i), y + b * Math.sin(i));
}
context.closePath();
context.stroke();
}

 椭圆的轨迹的思路是:通过循环,将极小的线段首尾相连,绘制了一个类似于椭圆的一个图像,但是由于线段太过细小导致了我们肉眼看上去就成了一个椭圆

运行的效果是:

椭圆上小球的运动实现

这个的制作思路跟上面的思路是一样的,所以这里就不再分析

这次我们就先看一看效果如何:

HTML代码和上面的例子相同

JavaScript代码如下:

var a=200,
b=100,
radius=30;
time=0;//循环的次数
window.onload=function(){
var canvas=document.getElementById('canvas');
canvas.height=768;
canvas.width=1024;
var cxt=canvas.getContext('2d');
centerPoint(cxt);
arcRoute(cxt,300,300,a,b,radius);
setInterval(function(){
arcRoute(cxt,300,300,a,b,radius);
}, 70);
}; //绘制原点
function centerPoint(cxt){
cxt.fillStyle="black";
cxt.beginPath();
cxt.arc(300,300,10,0,2*Math.PI,true)
cxt.closePath();
cxt.fill();
}
//椭圆路线绘制
function route(context,x,y,a,b){
var step = (a > b) ? 1 / a : 1 / b;
context.beginPath();
context.moveTo(x + a, y); //从椭圆的左端点开始绘制
for (var i = 0; i < 2 * Math.PI; i += step)
{
context.lineTo(x + a * Math.cos(i), y + b * Math.sin(i));
}
context.closePath();
context.stroke();
} //椭圆上小球运动的实现
function arcRoute(context,x,y,a,b,r){
context.clearRect(0,0,1024,768);
route(context,x,x,a,b);
centerPoint(context);
var step = (a > b) ? 1 / a : 1 / b;
context.fillStyle="red";
if(time==0){
context.beginPath();
context.arc(x,y,r,0,2*Math.PI,true);
context.closePath();
context.fill();
}else{
context.beginPath();
context.arc(x+a*Math.cos(time),y+b*Math.sin(time),r,0,2*Math.PI,true);
context.closePath();
context.fill();
}
time+=1;
}

四、相关的参考资料

火狐开发者中心

沈佳洋

好了,这一节的内容就先结束了,下一节预告,下一节:会谈谈一些其他的运动效果的实现和这些运动效果的另一种实现方式,同时还会有一些关于碰撞的检测等等的知识,敬请期待。如果有什么不懂或者是错误的地方,欢迎给位朋友在留言板留下你的想法,你的支持是我前进的动力

基于canvas实现物理运动效果与动画效果(一)的更多相关文章

  1. 基于canvas与原生JS的H5动画引擎

    前一段时间项目组里有一些H5动画的需求,由于没有专业的前端人员,便交由我这个做后台的研究相关的H5动画技术. 通过初步调研,H5动画的实现大概有以下几种方式: 1.基于css实现 这种方式比较简单易学 ...

  2. 2d旋转(css3实现过度效果和动画效果)

    效果: 源码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...

  3. 神奇的canvas——点与线绘制的绚丽动画效果

    代码地址如下:http://www.demodashi.com/demo/11636.html 前言 之前在某网站上看到了一个canvas绘制的动画效果,虽然组成的元素很简单,只有点和线,但是视觉效果 ...

  4. 类似nike+、香蕉打卡的转场动画效果-b

    首先,支持并感谢@wazrx 的 http://www.jianshu.com/p/45434f73019e和@onevcat 的https://onevcat.com/2013/10/vc-tran ...

  5. Android动画效果之Tween Animation(补间动画)

    前言: 最近公司项目下个版本迭代里面设计了很多动画效果,在以往的项目中开发中也会经常用到动画,所以在公司下个版本迭代开始之前,抽空总结一下Android动画.今天主要总结Tween Animation ...

  6. AndroidUI 视图动画-混合动画效果 (AnimationSet)/动画效果监听

    在前面介绍了几种动画效果:透明动画效果(AlphsAnimation).移动动画效果(TranslateAnimation).旋转动画效果(RotateAnimation).缩放动画效果(ScaleA ...

  7. 基于HTML5 Canvas粒子效果文字动画特效

    之前我们分享过很多超酷的文字特效,其中也有利用HTML5和CSS3的.今天我们要来分享一款基于HTML5 Canvas的文字特效,输入框中输入想要展示的文字,回车后即可在canvas上绘制出粒子效果的 ...

  8. 基于Rebound制造绚丽的动画效果-入门篇

    基于Rebound制造绚丽的动画效果-入门篇 Rebound是什么? Rebound是一个来自 Facebook 公司的 Java物理和动画库.Rebound spring 模型可用于创建动画,让你感 ...

  9. CodePen 作品秀:Canvas 粒子效果文本动画

    作品名称——Shape Shifter,基于 Canvas 的粒子图形变换实验.在页面下方的输入框输入文本,上面就会进行变换出对应的粒子效果文本动画. CodePen 作品秀系列向大家展示来自 Cod ...

随机推荐

  1. Access restriction: The type 'RSACipher' is not API

    解决方法: http://stackoverflow.com/questions/860187/access-restriction-on-class-due-to-restriction-on-re ...

  2. html页面高亮关键词

    function hightLightTheKeyWord(searchParam,$dom){ if(searchParam&&!/^\s*$/.test(searchParam)) ...

  3. linux 中/proc 详解

    proc 文件系统 在Linux中有额外的机制可以为内核和内核模块将信息发送给进程-- /proc 文件系统.最初设计的目的是允许更方便的对进程信息进行访问(因此得名),现在它被每一个有有趣的东西报告 ...

  4. Java报表工具FineReport常见的数据集报错错误代码和解释

    在使用finereport制作报表,若预览发生错误,很多朋友便手忙脚乱不知所措了,其实没什么,只要看懂报错代码和含义,可以很快的排除错误,这里我就分享一下finereport的数据集报错错误代码和解释 ...

  5. Java Web开发之Servlet获取ckeditor内容

    js: <!-- ckeditor插件 --> <script type="text/javascript" src="js/ckeditor/cked ...

  6. AC日记——矩阵交换行 openjudge 1.8 01

    01:矩阵交换行 总时间限制:  1000ms 内存限制:  65536kB 描述 给定一个5*5的矩阵(数学上,一个r×c的矩阵是一个由r行c列元素排列成的矩形阵列),将第n行和第m行交换,输出交换 ...

  7. 调用newtonsoft.json反序列出错

    调用newtonsoft.json反序列出错: Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current J ...

  8. poj[1185]炮兵阵地

    Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用&quo ...

  9. sublime text2安装package control的方法

    Package Control 方法一:在线安装,首先打开 Ctrl + ~,输入如下的代码: import urllib2,os; pf='Package Control.sublime-packa ...

  10. javascript中获取屏幕尺寸

    Javascript获取获取屏幕.浏览器窗口 ,浏览器,网页高度.宽度的大小 屏幕的有效宽:window.screen.availHeight屏幕的有效高:window.screen.availWid ...