11、《每周一点canvas动画》 —— 弹性动画

本系列文章代码文件

在上一章我们介绍了缓动动画,并且对弹性动画的概念做了简单的介绍。弹性动画(spring)与缓动动画都是基于距离的百分比动画,两者的不同之处在于,一个作用于速度(ease), 一个作用于加速度(spring)。弹性动画是动画中相当有用的的一个物理概念,通过它你可以做很多酷炫的效果,本节的主要内容如下:

  1. 简单的弹性动画

  2. 鼠标跟随弹性动画

  3. offset spring

  4. 总结

1.简单的弹性动画

之前我们已经说过弹性动画的作用元素是加速度。该加速度的变化基于距离的百分比。有了上一节对缓动动画的理解,想必大家对于我们要做什么应该都一清二楚了。这里我们先做一个基于坐标轴的弹性动画。先上效果图:

具体代码如下:

<canvas id="canvas" width="500" height="500" style="background-color: #000;">
    your browser not support canvas!
</canvas>

<script type="text/javascript" src="../js/utils.js"></script>
<script type="text/javascript" src="../js/ball.js"></script>
   <script>
       window.onload = function () {
          var canvas = document.getElementById('canvas'),
             context = canvas.getContext('2d'),
             ball = new Ball(),
             spring = 0.03,  //弹性系数
             targetX = canvas.width / 2,  //目标位置
             f = 0.95,
             vx = 0; 

             ball.y = canvas.height / 2;

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


        var dx = targetX - ball.x,  //目标位置减去小球的位置
            ax = dx * spring;  //距离乘以弹性系数

        vx += ax;
        vx *= f;
        ball.x += vx;
        ball.draw(context);
      }());
    };
    </script>

代码还是很简单的,这里我解释一下它的具体过程。

首先,我们设置了目标位置(targetX), 和弹性系数(spring),小球的初始位置位于canvas的左边缘,在动画循环中,每一帧都让目标的位置剪去小球的位置,然后将加速度(ax)赋值为距离(dx)与弹性系数(spring)的乘积,随着小球逐渐的向右运动(ball.x的增大),这样我们就得到一个逐渐衰减的加速度值。最终得到的效果就如图片中显示的一样,我们的目标位置是canvas画布的中心,小球以一个非常快的速度开始运动,因为此时的加速度很大,相应的速度值也很大,所以在一开始小球运动的很快。当小球快要到达目标位置时,小球不会立刻停止,为什么呢?因为虽然当小球靠近目标位置的时候,此时的加速度因为距离已经变得很小而逐渐趋近于零,但此时的速度却并不为零。所以,小球会超过目标位置继续运动。

当小球超过目标位置继续运动的时候,此时targetX - ball.x为负值,那么导致加速的值也为赋值,所以速度会在每一帧都加上一个负值的加速度,这样速度就开始慢慢减小,随着负值加速度的不断增大,速度逐渐减小至零,这时候小球就运动到了它能够到达的最远端。

当到达最远端,小球的速度变为零,但此时的加速度并不为零,此时的加速度值为一个负值。所以,速度值在随后开始从零变为负值,小球据开始从最远端往回走,当经过目标位置时,加速度又变为零,此时速度不为零继续向左运动,当超过零点加速度变为正值,速度开始减少,直至为零,让后就这样一直往复下去,最终停留在目标位置,这就是我们的弹性动画,简直和弹簧一样,有木有。

如果,你还能记得中学时关于速度与加速度的关系,你应该很容易就理解我所说的,加速度为零,速度不为零,速度为零,而加速度不为零

此后介绍的其他弹性动画,都是基于这个概念,至于形式的不同,只是增加或减少不同的控制元素。比如对于任意位置的弹性动画,就可以说是是上面简单动画的加强版。这里我们设置了一个任意的目标位置

var targetX = somewhere;
var targetY = somewhere;

然后,在动画循环中

var dx = targetX - ball.x,
    ax = dx * spring;
var dy = targetY - ball.y,
    ay = dy * spring;

    vx += ax;
    vy += ay;

2.鼠标跟随弹性动画

鼠标跟随是个老梗了,无非就是把目标位置设置为我们的鼠标。在这里我们把它作为我们渐进式增强学习的第二个动画。废话不多说我们上效果图:

具体代码图下:

window.onload = function(){
          var canvas = document.getElementById('canvas'),
          context = canvas.getContext('2d'),
          mouse = utils.captureMouse(canvas),
          ball = new Ball(20,"orange"),
          spring = 0.03, //弹性系数
          friction = 0.95, //摩擦力
          vx = 0,
          vy = 0;

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

        var dx = mouse.x - ball.x,  //核心代码
            dy = mouse.y - ball.y,
            ax = dx * spring,
            ay = dy * spring;

            vx += ax;
            vy += ay;
            vx *= friction;
            vy *= friction;
            ball.x += vx;
            ball.y += vy;
            ball.draw(context);
      }());
      }

这里我们定义了一个摩擦力,让运动更加逼真。具体的原理解释我就不在这多说了,前面已经说的很详细了。

2.1绳球运动

我一直在考虑这个运动到底应该取个什么样的名字。最后好像这个名字最能表现出该运动的运动元素,和运动形态。先看效果图,原理我们后面解释:

具体代码如下:

 。。。
context.save();
               context.beginPath();
               context.strokeStyle = "#fff";
               context.moveTo(ball.x, ball.y);
               context.lineTo(mouse.x, mouse.y);
               context.stroke();
               context.closePath();
               context.restore();
 。。。

在前面的鼠标跟随动画中,我们的目标位置鼠标,那么绳球运动的概念很简单,在鼠标与目标位置之间画个绳子,额,就是这么简单,说的我都不好意思了。你可以在后面再多追加几个小球看看会有什么样的效果。

3. Offset spring

在上面的动画中我们,小球的运动位置为我们设定的目标位置。offset 顾名思义为偏移量,它的作用是让物体最终停止在距离控制点一定距离的位置。比如:距离鼠标100像素的位置。这里我们给一个简单的例子:

具体代码在这我就不列出了,在文章的开头,有我们的源代码文件。如果感兴趣可以去看看。

4.缓动动画与弹性动画总结

1、缓动动画
var dx = targetX - object.x,
    dy = targetY - object.y;

var vx = dx * easing,
    vy = dy * easing;

    object.x += vx;
    object.y += vy;
2、缓动动画,精简形式
object.x += (targetX - object.x) * easing;
object.y += (targetY - object.y) * easing;
3、弹性动画
var ax = (targetX - object.x) * spring;
var ay = (targetY - object.y) * spring;

var vx += ax;
var vy += ay;

vx *= f;
vy *= f;

object.x += vx;
object.y += vy;
4、弹性动画,精简形式
vx += (targetX - object.x) * spring;
vy += (targetY - object.y) * spring;

object.x += (vx*=f);
object.y += (vy*=f);
5、 Offset spring
var dx = object.x - fixedX,
    dy = object.y - fixedY;
    angle = Math.atan2(dy, dx);
    targetX = fixed + Math.cos(angle)*springLength,
    targetY = fixed + Math.sin(angle)*springLength;

    //spring to targetX, targetY as above

下一章,碰撞检测,应该是本系列最难的一章,做好准备。

展开阅读全文

没有更多推荐了,返回首页