8、《每周一点canvas动画》——边界检测与摩擦力(2)

本文介绍了两种在物理仿真中实现摩擦力的方法,并通过实例展示了如何应用这些方法来模拟物体在运动过程中的减速现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

到目前为止,我们最常见的两种情形:

  1. 物体按照一定的速度做任意运动直到碰上边界

  2. 物体自身,或者通过外部的作用力,运用加速度来改变物体的速度

不管怎样,除非我们主动设置物体在哪停住,或是撞击什么物体,否则物体就会以一定的速度朝着某个方向一直做运动。但是在现实世界中,这是不可能的,我们周围有太多的东西会阻碍一个物体的运动,比如空气阻力等,它会让物体的运动速度持续衰减,最终为零。这一节,我们主要探讨摩擦力的使用,包括:

  • 摩擦力的两种使用方法

  • 摩擦力的应用

  • 本章总结

1.摩擦力的两种使用方法

关于摩擦力的两种使用方法,其实都大同小异。现在我们来介绍第一种方法,况且叫它正规的方法。摩擦力的作用是减小物体的运动速度,那么就意味着你需要定义一个变量f(代表摩擦力),让速度在每一帧都减去它,直至为零。假设现在我们有一个物体,它的速度分量分别为vx,和vy。那么我们首先要做的是计算物体运动的角度(angle),其次是物体运动的总的速度(speed),通过前面章节学习,我们很容易的就可以计算出来:

    var angle = Math.atan(vy, vx);
    var speed = Math.sqrt(vx*vx + vy*vy);

然后,在动画循环中这样设置:

    if(speed > f){
        speed -= f;
    }else{
        speed = 0;
    }

最后你需要把每一帧得到的新的速度再重新分解到水平方向和竖直方向

    vx = Math.cos(angle) * speed;
    vy = Math.sin(angle) * speed;

ok,让我们来看看运行效果吧!

具体代码,如下:

    <canvas id="canvas" width="500" height="500" style="background:#000;">
           your browser not support canvas!
       </canvas>
       <script src="../js/utils.js"></script>
       <script src="../js/ball.js"></script>
       <script>
           window.onload = function(){
               var canvas = document.getElementById("canvas");
               var context = canvas.getContext('2d');

               var ball = new Ball(20, "red");
               ball.x = canvas.width/4;
               ball.y = canvas.height/4;

               var f = 0.05, speed = 0, angle = 0;//设定摩擦力

               var vx = Math.random()*10 -5;
               var vy = Math.random()*10 -5;

               (function drawFrame(){
                   window.requestAnimationFrame(drawFrame, canvas);
                   context.clearRect(0, 0, canvas.width, canvas.height);

                   speed = Math.sqrt(vx*vx + vy*vy);
                   angle = Math.atan2(vy, vx);

                   if(speed > f){
                       speed -= f; //通过摩擦力减小速度
                   }else{
                       speed = 0;
                   }

                   vx = Math.cos(angle) * speed;
                   vy = Math.sin(angle) * speed;

                   ball.x += vx;
                   ball.y += vy;

                   ball.draw(context);
               }());
           }
        </script>

具体的代码前面已经有了详细的解释。在这我就不重复说明了,示例中的物体的运动角度都是恒定的,你也可以在每一帧里改变物体的运动角度,看看会出现什么不一样的效果。

另一种关于摩擦力的使用,我们况且叫它简易摩擦力的使用,这里我给出部分代码:

    (function drawFrame(){
                   window.requestAnimationFrame(drawFrame, canvas);
                   context.clearRect(0, 0, canvas.width, canvas.height);

                   //每一帧都乘以摩擦力变量
                   vx *= f;
                   vy *= f;

                   ball.x += vx;
                   ball.y += vy;
                   ball.draw(context);
               }());

当然,为了减少计算机的计算量,提升性能,你可以在后面加个判定条件:

    if(Math.abs(vx) > 0.001){
        vx *= f;
        ball.x += vx
    }
    if(Math.abs(vy) > 0.001){
        vx *= f;
        ball.y += vy
    }

2.摩擦力的应用

摩擦力的应用这一部分,我们仍旧使用之前太空船的例子(我知道很简陋,但不要吐槽了)。

具体代码如下:

<script>
        window.onload = function(){
            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");

            var ship = new SpaceShip();
                ship.x = canvas.width/2;
                ship.y = canvas.height/2;

            var f = 0.97,vr = 0, vx = 0, vy = 0, ax = 0, ay = 0, speed = 0, angle = 0;

            window.addEventListener("keydown", function(event){
                switch (event.keyCode){
                    case 37:
                        vr = -3;
                        break;
                    case 39:
                        vr = 3;
                        break;
                    case 38:
                        speed = 0.5;
                        ship.showFlame = true;
                        break;
                }
            }, false);
            window.addEventListener("keyup", function(event){
                vr = 0;
                speed = 0;
                ship.showFlame = false;
            }, false);

            (function drawFramw(){
                window.requestAnimationFrame(drawFramw, canvas);
                context.clearRect(0, 0, canvas.width, canvas.height);

                ship.rotation += vr * Math.PI/180;
                angle = ship.rotation;

                ax = Math.cos(angle)*speed;
                ay = Math.sin(angle)*speed;

                vx += ax;
                vy += ay;

                //摩擦力
                vx *= f;
                vy *= f;

                ship.x += vx;
                ship.y += vy;

               //边界检测
               if(ship.x + ship.width/2 > canvas.width){
                   ship.x = canvas.width - ship.width;
                   vx *= -1;
               }else if(ship.x < ship.width/2){
                   ship.x = ship.width/2;
                   vx *= -1;
               }
               if(ship.y + ship.height/2 > canvas.height){
                   ship.y = canvas.height - ship.height/2;
                   vy *= -1;
               }else if(ship.y < ship.height/2){
                   ship.y = ship.height/2;
                   vy *= -1;
               }
                ship.draw(context);
            }());
        }
    </script>

都是老例子了,只是增加了摩擦力那部分的代码,如果有什么不明白的,欢迎评论!

3.本章总结

        // 1.移除一个超过边界的物体
        if(object.x - object.width/2 > right || 
           object.x + object.width/2 < left ||
           object.y - object.height/2 > bottom ||
           object.y + object.height/2 < top){
            //移除物体代码
           }

        // 2.重现一个超出边界的物体
        if(object.x - object.width/2 > right || 
           object.x + object.width/2 < left ||
           object.y - object.height/2 > bottom ||
           object.y + object.height/2 < top){
            //重新设置对象的位置和速度
           }

        //3. 边界环绕
        if(object.x - object.width/2 > right){
            object.x = left - object.width/2;
        }else if(object.x + object.width/2 < left){
            object.x = object.width/2 + right;
        }
        if(object.y - object.height/2 > bottom){
            object.y = top - object.height/2;
        }else if(object.y + object.height/2 < top){
            object.y = object.height/2 + bottom;
        }

        //4.摩擦力(正规军)
        speed = Math.sqrt(vx*vx + vy*vy);
        angle = Math.atan2(vy, vx);
        if(speed > f){
             speed -= f;
        }else{
            speed = 0;
        }
        vx = Math.cos(angle)*speed;
        vy = Math.sin(angle)*speed;

        //4.摩擦力(野战军)
          vx *= f;
          vy *= f;

好了,关于边界检测和摩擦力这一章的主要内容都在上面了,方法都已经告诉你了,能做出什么样的效果,就看各位的想象力了。基本上关键的物理概念和数学公式都已经讲完了,在后面的几章我们主要讲解一些常见的运动形式,比如缓动动画,弹性动画等。敬请期待下一章——就是扔着玩。
最后,啰嗦一句,讲过的代码文件,以后我会在每一章的开头附上地址!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值