简单的弹性动画
鼠标跟随弹性动画
offset spring
总结
之前我们已经说过弹性动画的作用元素是加速度。该加速度的变化基于距离的百分比。有了上一节对缓动动画的理解,想必大家对于我们要做什么应该都一清二楚了。这里我们先做一个基于坐标轴的弹性动画。先上效果图:
具体代码如下:
- <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, //弹性系数 B5教程网 www.bcty365.com
- 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;
鼠标跟随是个老梗了,无非就是把目标位置设置为我们的鼠标。在这里我们把它作为我们渐进式增强学习的第二个动画。废话不多说我们上效果图:
具体代码图下:
- 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);
- }());
- }
这里我们定义了一个摩擦力,让运动更加逼真。具体的原理解释我就不在这多说了,前面已经说的很详细了。
我一直在考虑这个运动到底应该取个什么样的名字。最后好像这个名字最能表现出该运动的运动元素,和运动形态。先看效果图,原理我们后面解释:
具体代码如下:
- 。。。
- ontext.save();
- context.beginPath();
- context.strokeStyle = "#fff";
- context.moveTo(ball.x, ball.y);
- context.lineTo(mouse.x, mouse.y);
- context.stroke();
- context.closePath();
- context.restore();
- 。。。
在前面的鼠标跟随动画中,我们的目标位置鼠标,那么绳球运动的概念很简单,在鼠标与目标位置之间画个绳子,额,就是这么简单,说的我都不好意思了。你可以在后面再多追加几个小球看看会有什么样的效果。
在上面的动画中我们,小球的运动位置为我们设定的目标位置。offset
顾名思义为偏移量,它的作用是让物体最终停止在距离控制点一定距离的位置。比如:距离鼠标100像素的位置。这里我们给一个简单的例子:
具体代码在这我就不列出了,在文章的开头,有我们的源代码文件。如果感兴趣可以去看看。
- var dx = targetX - object.x,
- dy = targetY - object.y;
- var vx = dx * easing,
- vy = dy * easing;
- object.x += vx;
- object.y += vy;
- object.x += (targetX - object.x) * easing;
- object.y += (targetY - object.y) * easing;
- 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;
- vx += (targetX - object.x) * spring;
- vy += (targetY - object.y) * spring;
- object.x += (vx*=f);
- object.y += (vy*=f);
下一章,碰撞检测,应该是本系列最难的一章,做好准备。
- 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