PHP群:95885625 Hbuilder+MUI群:81989597 站长QQ:634381967
    您现在的位置: 首页 > 开发编程 > HTML5+CSS3教程 > 正文

    《html5 canvas动画》——万有引力

    作者:admin来源:网络浏览:时间:2020-09-30 00:07:50我要评论
    导读:本章介绍,另一个动画应用——万有引力。听起来似乎有些玄乎,但是多事情千万不要被表面现象所迷惑!言归正传,不管是地球上的是物体,还是...
    本章介绍,另一个动画应用——万有引力。听起来似乎有些玄乎,但是多事情千万不要被表面现象所迷惑!言归正传,不管是地球上的是物体,还是宇宙中的星辰,物体与物体之间总是存在着一种看不见摸不着的的力场作用,这也就是为什么牛顿会被苹果砸,地球会围绕太阳做运动。

    在上一章我们讲解动量守恒,让很多人头疼不已。我发现看的人很少,因为那应该算是这个系列最难的部分了吧,我心中始终坚信:让自己难受的,就是能够让自己成长的,希望你也坚信这一点!下面我们介绍如何把万有引力应用于我们的动画效果中。

    万有引力

    百度百科上这样说:

    任意两个质点有通过连心线方向上的力相互吸引。该引力大小与它们质量的乘积成正比与它们距离的平方成反比,与两物体的化学组成和其间介质种类无关

    简单来说,就是两个物体,他们之间存在一种引力,满足如下表达式:

    1
    
    force = G * m1 * m2 / distance^2
    

     

    其中,m1 和m2是物体的质量,distance是物体间的距离,G是引力常数,是个非常小的值6.674*10^-11。在动画中可以忽略这个值。最后,表达式就变为

    1
    
    force = m1 * m2 / distance^2
    

     

    粒子

    还是老规矩,先上效果图:

    《html5 canvas动画》——万有引力

    注意效果图中,我们并没有给动画中的粒子设置任何的速度,但是粒子却发生了移动。下面我们来具体分析代码的实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    
    <script>
        window.onload = function(){
            var canvas = document.getElementById('canvas'),
                context = canvas.getContext('2d'),
                particles = [],
                numParticles = 50;
                
         	//创建粒子
            for(var particle, i=0; i<numParticles; i++){
                particle = new Ball(5,"orange");
                particle.x = Math.random()*canvas.width;
                particle.y = Math.random()*canvas.height;
                particle.mass = 1;
                particles.push(particle);
            }
            
            //绘制粒子
            function draw(particle){
                particle.draw(context);
            }
           
           //引力函数
            function gravitate(partA, partB){
                var dx = partB.x - partA.x;
                var dy = partB.y - partA.y;
                var distQ = dx*dx + dy*dy;		   //计算物体建的距离
                var dist = Math.sqrt(distQ);		   //距离的平方
                var F = (partA.mass * partB.mass)/distQ;  //万有引力公式
                
                var ax = F * dx/dist;		//作用力作用于加速度
                var ay = F * dy/dist;		
                
                partA.vx += ax/partA.mass;	//加速度作用于速度
                partA.vy += ay/partA.mass;
                partB.vx -= ax/partB.mass;
                partB.vy -= ay/partB.mass;
            }
            
            //移动函数
            function move(partA, i){
                partA.x += partA.vx;
                partA.y += partA.vy;
                
                for(var partB, j=i+1; j<numParticles; j++){
                    partB = particles[j];
                    //引力
                    gravitate(partA, partB);
                }
            }
            //动画循环
            (function drawFrme(){
                window.requestAnimationFrame(drawFrme, canvas);
                context.clearRect(0 ,0, canvas.width, canvas.height);
                
                particles.forEach(move);        //移动
                particles.forEach(draw);		//绘制
            }())
        }
    </script>
    

     

    代码很简单,这里主要讲一下引力函数。在引力函数中,我们传入两个物体作为参数partApartB。首先,计算两物体间的距离。然后,带入公式中计算引力的大小。

    物体间的引力分解到水平和竖直两个方向,作用于物体的加速度,注意这里的分解方式比较隐晦,用的是dx/dist,相当于cos值。最后,将物体的加速度作用于速度。

    在移动函数中,我们引入的是多物体碰撞检测策略,保证粒子与粒子之间的相互作用,同时提高了程序的高效性,关于它的具体分析你可以看《每周一点canvas动画》——碰撞检测(2)这里就不多解释了,源代码文件gravity.html

    加入碰撞检测

    注意上面的动画效果中,当两个粒子考的非常近的时候,并没有发生碰撞,如果你想要然两物体间发生碰撞效果,我们只需要在move函数中中加入碰撞检测的代码即可!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    function move (partA, i) {
            partA.x += partA.vx;
            partA.y += partA.vy;
        for (var partB, j = i + 1; j < numParticles; j++) {
            partB = particles[j];
            checkCollision(partA, partB); //碰撞检测
            gravitate(partA, partB); //万有引力
        }
    }
    

     

    碰撞检测的代码是《每周一点canvas动画》——桌球运动(2)中有详细的解释,完全一模一样只需要拿过来用就好了,这里我就不做过多解释了,我们直接看效果图, 源代码文件gravity-bounce.html

    《html5 canvas动画》——万有引力

     

    太阳系

    既然是万有引力,那怎么少的了我们经典的太阳系。当然你完全可以不使用万有引力来做物体的轨道运动,只需要使用简单的三角函数就可以让物体做圆形环绕和椭圆环绕,但是那都不是真的。ok,在这我们只是简单的做一个水星,金星,地球围绕太阳的运动,其他的星球你可以自己往上加。

    《html5 canvas动画》——万有引力

    代码与上面加入碰撞效果的代码一样,唯一不同的是我们只引入了4个物体,每一个物体都有不同的质量,和初速度等属性,比如太阳的各项属性:

    1
    2
    3
    4
    
    sun.x = canvas.width/2;
    sun.y = canvas.height/2;
    sun.mass = 10000;
    particles.push(sun);
    

     

    太阳的质量非常大,有10000,看下我们的地球:

    1
    2
    3
    4
    5
    
    earth.x = canvas.width/2+300;
    earth.y = canvas.height/2;
    earth.mass = 1;
    earth.vy = 5.8;
    earth.name = "地球";
    

     

    地球的质量很小,只有1.并且它有一个竖直的速度vy,为的就是让地球在一开始在竖直方向做运动,这样太阳对地球的引力就会使它偏离原来的运动方向,经过合适的调试,可以得到一个完美的绕太阳做圆周运动的地球。

    这里解释两个我认为比较重要的点:

    第一个,为什么说要经过调试呢?你可以打开源代码试试改变地球的速度。你会发现当把地球的速度改小的时候,地球会被太阳吸到自己的身上,和地球上的飞机由于速度限制无法逃离地球一个道理。当你加大地球的速度,你就会发现太阳的引力不足以把地球拉向自身,就会发生地球逃逸的想象。

    第二个,为什么太阳没动呢?在我们的代码中,你应该会注意到在将加速度作用于物体的速度上时,我们并不是直接让速度值与加速度相加,而是:

    1
    2
    3
    4
    
    partA.vx += ax/partA.mass;	//加速度作用于速度
    partA.vy += ay/partA.mass;
    partB.vx -= ax/partB.mass;
    partB.vy -= ay/partB.mass;
    

     

    让加速度的大小除以物体的质量。所以你会发现,太阳纹丝不动,那是因为它的质量太大,其他星球对它的影响微乎其微,这是不是十分的合乎情理呢?你可以试着让地球的质量也很大,那么你就会发现,太阳也移动了!

    具体代码,请查看:orbit.html

    粒子花园

    和上一章《每周一点canvas动画》——桌球运动(2)中结尾处的粒子效果不一样,尝尝万有引力的粒子效果是个什么味道。

    《html5 canvas动画》——万有引力

    由于电脑太实在不行了,可能你看到的效果有些卡,但实际效果完全不同,你运行源码尝试一下。代码没什么难的,我们只是让物体之间的距离如果小于某个值时就连线。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    if (dist < minDist) {                   
                    context.save();
                    context.strokeStyle = "rgba(255,255,255,.3)";
                    context.beginPath();
                    context.moveTo(ballA.x, ballA.y);
                    context.lineTo(ballB.x, ballB.y);
                    context.closePath();
                    context.stroke();
                    context.restore();  
    }
    

     

    具体代码,请看node-garden-line.html

    总结

    本章重要公式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    function gravitate(partA, partB){
         var dx = partB.x - partA.x;
         var dy = partB.y - partA.y;
         var distQ = dx*dx + dy*dy;
         var dist = Math.sqrt(distQ);
         var F = (partA.mass * partB.mass)/distQ;
                   
         var ax = F * dx/dist;
         var ay = F * dy/dist;
                   
         partA.vx += ax/partA.mass;
         partA.vy += ay/partA.mass;
         partB.vx -= ax/partB.mass;
         partB.vy -= ay/partB.mass;
     }
    

     

    到这里,我们的这个系列的前半部分就介绍完了,如果这些你都掌握了,结合canvas的API, 你完全可以做出很多绚丽的动画效果。下一部分,我们介绍canvas动画的黑科技——3D。不是webGL, 就是在2d的canvas平面实现三维效果,敬请期待!

    转载请注明(B5教程网)原文链接:https://b5.mxunkeji.com/content-142-5424-1.html
    相关热词搜索: