基于canvas实现物理运动效果与动画效果(一)

一、为什么要写这篇文章

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

二、几种简单的直线运动

这一部分主要讲解的是简单的运动效果的实现原理,其实所有的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;
}

四、相关的参考资料

火狐开发者中心

沈佳洋

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

时间: 2024-10-31 22:13:49

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

66种基于animate.css的CSS消息提示动画效果

这是一款基于animate.css的效果非常酷的CSS消息提示动画效果.这66种CSS消息提示动画效果按出现位置分为4种类型:上部.中部.中下和右下.每个部位的消息提示效果都是不一样的. 注意:这个CSS消息提示动画效果需要在支持CSS3的浏览器中才能正常工作. 在线演示:http://www.htmleaf.com/Demo/201503061471.html 下载地址:http://www.htmleaf.com/css3/css3donghua/201503061470.html

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

首先,支持并感谢@wazrx 的 http://www.jianshu.com/p/45434f73019e和@onevcat 的https://onevcat.com/2013/10/vc-transition-in-ios7/ 对于转场动画的讲解和实现,非常详细,本人也是看过他们的文章后受的启发,快速实现了基于本项目需求的转场动画效果. 效果如下:(gif是我们的美术大师帮忙做的演示动效,实际的效果要比这个好,可通过文章最后链接下载我们的app:柠檬跑步,查看效果) 地图切换.gif 我的需

Android动画效果——1.帧动画2.补间动画3.跳转画面(三)

Android--动画效果1.帧动画2.补间动画3.跳转画面 插值器类 xml属性值 说明 LinearInterpolator @android:anim/linear_interpolatorr 动画以均匀的速度改变. AccelerateInterpolator @android:anim/accelerate_interpolator 在动画开始时改变速度较慢,然后开始加速. AccelerateDecelerateInterpolator @android:anim/accelerat

Android开发之动画效果浅析

Android开发之动画效果浅析 请尊重他人的劳动成果,转载请注明出处:Android开发之动画效果浅析 程序运行效果图: Android动画主要包含补间动画(Tween)View Animation.帧动画(Frame)Drawable Animation.以及属性动画Property Animation.下面依次介绍一下各个动画. 1.   补间动画(Tween) Tween动画,通过对View 的内容进行一系列的图形变换 (包括平移.缩放.旋转.改变透明度)来实现动画效果.动画效果的定义可

想给UIVIew上控件添加一些动画效果

如果你还不知道怎样让一张图片缓缓滑动,渐渐消失,或者是在原地翻滚,不知道怎样让一个窗口弹出的时候有一点抖动的效果不那么僵硬,那正好,今儿在下总结的内容可能刚好能帮你实现你想要的效果(⊙o⊙)哦. 首先说一下什么是动画效果,动画效果有哪些好处吧: 这里所说的动画绝对不是你在电视上看到的,有剧情的那种(当然这句可能是废话),而是为了增加用户的体验感,通过对控件的属性或者layer进行一些处理达到美化界面的效果,主要是让界面看起来更加的生动,不会太枯燥.想象一下,你在用读书软件时候的翻页效果,就能被称

Android学习——Animation动画效果

1.Android动画模式: 1>tweened animation: 渐变动画: 2>frame by frame: 画面转换动画. 2.Android的Animation动画由四种类型组成: XML alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面转移旋转动画效果 Java代码 AlphaAnimation 渐变透明度动画效果 ScaleAnimation 渐变尺寸伸缩动画效果 TranslateAnimat

jQuery学习——动画效果

动画效果 基本动画效果 隐藏匹配元素 $("img").hide(300);//将img隐藏300ms 显示匹配元素 $("img").show(300);//在300ms内显示img 元素状态切换 $(document).ready(function(){ $("input[type='button']").click(function() { $("div").toggle();//若果元素可见,切换为隐藏,如果元素隐藏,

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

前言: 最近公司项目下个版本迭代里面设计了很多动画效果,在以往的项目中开发中也会经常用到动画,所以在公司下个版本迭代开始之前,抽空总结一下Android动画.今天主要总结Tween Animation(补间动画). Tween Animation(补间动画): Tween动画,通过对View的内容进行一系列的图形变换 (包括平移.缩放.旋转.改变透明度)来实现动画效果.动画效果的定义可以采用XML来做也可以采用编码来做. 动画类型 XML配置方式 Java代码实现方式 渐变透明度动画效果 <al

Jquery基础篇6___动画效果

最近由于太忙,总是没有时间写东西,不是有句古话说时间似海绵中的水,挤挤总会有的,但感觉当了程序员之后,总是在忙着写代码,忙着学新技术,时间本来就不够,想挤挤时间抽空写点东西,总是挤不出来.忙里偷得半日闲,有时间还是写写比较好.有时候感觉自己写的这些东西不是很多人都有吗,而且Jquery官网上写的要比自己好多了,但是写自己的东西总会有自己的理解,有自己的想法在其中,而且印象也比较深刻.学过Jquery的人,肯定会感觉自己当时候照着例子的时候会,真正要写大型的JS代码的时候,却总写不出来,而且过不了