10、《每周一点canvas动画》——移动物体(2)

本系列文章代码文件

在上一节《每周一点canvas动画》——移动物体(1)中我们介绍了如何捕获一个物体,并且对物体进行拖拽。首先,我们在小球的原型对象上添加了一个方法getBounds(),该方法的作用是返回一个对象,该对象内包含小球的坐标和长宽属性值,并且在我们的工具函数utils.js中也添加了一个方法containPoints(rect, x, y),该方法传入3个参数:对象rect,坐标x和y,返回一个布尔值用于判定我们的鼠标是否点击在了小球上。

然后,我们为canvas添加监听事件,当鼠标点击到了小球上时,判定为小球被鼠标捕获,这时如果你移动鼠标小球就会随着鼠标的位置而移动,当鼠标抬起移除监听事件,小球不再随鼠标移动,这样就完成了我们移动物体的目的。这一节我们主要介绍:

  1. 运动物体的捕获

  2. 物体的抛扔

  3. 总结

1.运动物体的捕获

在上一节中我们知道了,如何移动一个物体。那么,这一节我们更深入些,首先就来探讨如何捕获一个运动的物体。不过总体的思路还是沿用上一节已经搭建好的框架,我们所要做的就是发挥我们的想象力。。。

现在我们理一下要完成这个动画需要做哪些事情。

  1. 既然是捕获运动中的物体,那么一定要让我们的小球动起来。这个很容易,前面的章节都介绍过了,我们只需要让小球的坐标值加上其速度值就好了,如果你想更逼真一些,就加个加速度或者再来个摩擦力。

  2. 为了方便起见我们必须设置边界,避免小球超出canvas消失不见。

  3. 我们必须设置一个开关变量来保证当鼠标点击在了小球上,小球不再做自由运动,而改由跟随鼠标做运动。

ok,现在我们来做代码上的实现!首先是前两步:

//定义函数moveAndBoun
function moveAndBoun(){
               var left = canvas.width,
                   right = 0,
                   top = 0,
                   bottom = canvas.height;

               //让小球动起来
               ball.x += vx;
               vy += gravity;
               ball.y += vy;
               //边界检测
               if(ball.x + ball.radius > left){
                   vx *= bounce;
                   ball.x = left - ball.radius;
               }else if(ball.x - ball.radius < right){
                   vx *= bounce;
                   ball.x = ball.radius; 
               }
               if(ball.y + ball.radius > bottom){
                   vy *= bounce;
                   ball.y = bottom - ball.radius;
               }else if(ball.y - ball.radius < top){
                   vy *= bounce;
                   ball.y = ball.radius;
               }
           }

我们把让小球运动和边界检测放到了一个函数里。这样很方便通过开关变量来调用。

第三步定义开关变量,并在动画循环中调用它,用来控制小球是自用运动还是跟随鼠标一起运动。当鼠标按下时isMousedown变为true,抬起是变为false。

var isMousedown = false;

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

                //如果没有捕获则自由运动
               if(!isMouseDown){
                   checkBoundries();
               }
               ball.draw(context);
           }());

现在让我们来看看动画效果

完整的代码我已经托管到了gitHub上,你可以通过点击文章开头的链接获取。注意动画中,我有一个尝试扔小球的动作,但是它并没有按我们所想象的那样呈抛物线飞出去,这是因为当鼠标抬起时我们设定了小球的水平速度(vx)为零,只有纵向的速度与加速度,所以这里我们要做个简单的改进,来达到让小球飞出去的效果。

2.物体的抛扔

物体的抛扔在动画中怎样描述呢?它意味着你点击一个物体并且以一定的方向开始移动它,当你释放它时,物体沿着你拖拽的方向继续移动,是不是跟我们平时扔东西一模一样。

那么当小球扔出去后,它的运行速度怎么计算呢?你可以直接在水平方向重新给它设定一个速度(vx),甚至你也可以设置竖直方向的速度(vy),这样当你释放一个小球的时候,它就会按照你新设定的速度运动。但是,这有一个问题,那就是绝对的不真实。想想你平时扔一个东西,物体脱离你手后的运行速度是根据你在扔这个物体的时间段内,物体运动的距离决定的。换言之,也就是说你扔的越快,物体脱离你手后运动的速度就越快。

在canvas中,物体的位置变化由速度决定,即 oldPosition + velocity = newPosition。稍做变形,就可以得出velocity = newPosition - oldPosition,这样我们就得出了物体释放时的运行的速度。

这里有几个比较关键的点必须说明,什么时候算是oldPosition,什么时候算是newPosition。当你拖动一个物体,物体在每一帧都会有一个newPosition,而oldPosition就是物体在上一帧的位置。如果你使用requesstAnimationFrame()方法做动画循环,每一帧的时间间隔会不一样,不过基本上都是在十几毫秒左右,你的oldPosition就是十几毫秒前(也就是上一帧)的位置,newPosition就是十几毫秒后(下一帧)的位置。现在清楚了吧!

看看我们给的公式,不难发现,速度的大小取决于在一帧中运动的距离,也就是新位置与旧的位置之间的差值。这样就跟我们现实中完全一样了。

ok!现在来看看动画效果。

具体代码如下:

  <p id="record">当前的速度为:</p>
   <canvas id="canvas" width="1000" height="600" 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'),
               oP = document.getElementById('record'),
               context = canvas.getContext('2d'),
               ball = new Ball(30, "orange"),
               vx = Math.random()*10 + 5,
               vy = -10,
               bounce = -0.8,
               gravity = 1.8,
               speed, //speed 用于记录速度值
               oldX, oldY; //定义变量oldX, oldY

           var isMouseDown = false,
               mouse = utils.captureMouse(canvas),
               w = 0, h = 0;

               ball.x = canvas.width/2;
               ball.y = canvas.height/2;           

           canvas.addEventListener("mousedown", function(event){
               if(utils.containsPoint(ball.getBounds(), mouse.x, mouse.y)){
                   w = mouse.x - ball.x;
                   h = mouse.y - ball.y;

                  //如果点击到了小球上,那么分别将小球的位置赋值给oldX, oldY
                  //并且随着小球的移动oldX和oldY每一帧都在刷新
                   oldX = ball.x;
                   oldY = ball.y;

                   isMouseDown = true;

                   canvas.addEventListener('mouseup', onMouseUp ,false);
                   canvas.addEventListener('mousemove', onMouseMove, false);
               }
           }, false);

           function onMouseUp(e){...}
           function onMouseMove(e){...}           
           function moveAndBoun(){...}

           //计算抛出速度
           function trackVelocity(){
                  //用当前小球的位置减去上一帧的坐标
               vx = ball.x - oldX;
               vy = ball.y - oldY;

               //重新赋予oldX和oldY
               oldX = ball.x;
               oldY = ball.y;

               speed = Math.sqrt(vx*vx + vy*vy);
               oP.innerHTML = "当前的速度为:"+speed.toFixed();
           }

           (function drawFrame(){
               ...

               //调用
               if(!isMouseDown){
                   checkBoundries();
               }else{
                   trackVelocity();
               }

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

从动画中我们可以看出,当我们快速移动小球后,小球脱离鼠标后的运动速度很快。当我们缓慢移动的时候小球的移动速度很慢,由于我们定义的重力加速度比较大,你会看到小球快速的向下方坠落。在上方,我做了一个速度值得计算,来让效果更叫明显,可以直观的看到速度值得变化。

3.总结

本章主要学习了用户与canvas中的物体的交互,物体的移动,拖拽和抛扔。核心代码如下:

//得到球体坐标
Ball.prototype.getBounds = function(){
    return {
        x: this.x - this.radius,
        y: this.y - this.radius,
        width: this.radius*2,
        height: this.radius*2
    };
}
//捕获物体
utils.containsPoint = function(rect, x, y){
    return !(x<rect.x || x>rect.x + rect.width ||
             y<rect.y || y>rect.y + rect.height);
}

//物体的移动拖拽
canvas.addEventListener("mousedown", function(event){
      if(utils.containsPoint(ball.getBounds(), mouse.x, mouse.y)){
            ...
            canvas.addEventListener('mouseup', onMouseUp ,false);
            canvas.addEventListener('mousemove', onMouseMove, false);
           }
      }, false);


//理解物体的抛扔的概念
vx = ball.x - oldX;
vy = ball.y - oldY

下一节,开始介绍高级动画,缓动动画和弹性动画,敬请期待!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值