简单缓动
在我们使用缓动使物体归位时,运动显得很自然。简单的缓动运动实现起来也非常简单,比求出夹角,计算 vx,vy 还要简单。下面是缓动的实现策略:
1. 确定一个数字作为运动比例系数,这是个小于 1 的分数;
2. 确定目标点;
3. 计算物体与目标点的距离;
4. 用距离乘以比例系数,得出速度向量;
5. 将速度向量加到当前物体坐标上;
6. 重复 3 到 5 步。图 8-1 解释了这一过程。
我们先来解释一下这个过程,看看在 ActionScript 中是怎样实现的。
首先,确定一个分数作为比例系数。我们说过,速度与距离是成比例的。也就是说速度是距离的一部分。比例系数在 0 和 1 之间,系数越接近 1,运动速度就会越快;系数越接近0,运动速度就会越慢。但是要小心,系数过小会使物体无法到达目标。开始我们以 0.2 作为系数,这个变量名就叫 easing。初始代码如下:
var easing:Number = 0.2;
接下来,确定目标。只需要一个简单的 x,y 坐标,选择舞台中心坐标再合适不过了。
var targetX:Number = stage.stageWidth / 2;
var targetY:Number = stage.stageHeight / 2;
下面,确定物体到达目标的距离。假设已经有一个名为 ball 影片,只需要从 ball 的 x,y 坐标中减去目标的 x,y。
var dx:Number = targetX - ball.x;
var dy:Number = targetY - ball.y;
速度等于距离乘以比例系数:
vx = dx * easing;
vy = dy * easing;
下面,大家知道该怎么做了吧:
ball.x += vx;
ball.y += vy;
最后重复步骤 3 到步骤 5,因此只需加入 enterFrame 处理函数。
缓动何时停止
在物体缓动运动到目标点时,物体最终会到达目标点并且完成缓动效果。但是,即使不显示该对象,缓动代码仍在执行中,这一来浪费了 CPU 资源。当物体到达目标时,应该停止执行代码。判断物体是否到达目标的方法非常简单,就像这样:
if(ball.x == targetX && ball.y == targetY) {
// code to stop the easing
}
但是这里要注意一些技巧。
我们所讨论的缓动类型涉及到了著名的 Xeno 悖论。Xeno 也是位希腊人,爱好测量实验。Xeno 将运动分解为下面几个步骤:物体要从 A 点到达 B 点,它首先要移动到两点间一半的距离。然后物体再从该点出发,到达与 B 点距离一半的距离。然后再折半。每次只移动离目标一半的距离,但永远无法准确地达到目标。
这个悖论听起来是非常符合逻辑的。但是很明显,我们确实将物体从一点移动到了另一点,这样看来他的说法有些问题。到 Flash 中看看,影片在 x 轴上的位置为 0,假设要将它移动到 x 轴为 100 的位置。按照悖论所说,设缓动系数为 0.5,这样每次运动到离目标一半的距离。过程如下:
■ 从 0 点开始,经过 1 帧,到达 50。
■ 第 2 帧,到达 75。
■ 剩下的距离是 25。它的一半是 12.5 ,所以新的距离就是 87.5。
■ 按照这种顺序,位置将变化为 93.75, 96.875, 98.4375 等等。20 帧以后,将到达 99.999809265。
从理论上讲位置越来越接近目标,但是永远无法准确地到达目标点。然而,在代码中进行试验时,结果就发生了一些微妙的变化。归根结底问题就在于“一次最少能移动多少个像素”,答案是 1/20。事实上,二十分之一像素有个特有的名字:twip (缇)。在 Flash 内部计算单位都采用 twip 像素,包括所有 Sprite 影片,影片剪辑和其它舞台对象。因此,在显示影片位置时,这个数值永远是 0.05 的倍数。
一个影片要到达 100 的位置,而它所到达的最接近的位置事实上是 99.5。再分隔的距离,就是加上 (100 – 99.95) /2。相当于加上了 0.025,四十分之一像素。超出了 twip 是能够移动的最小值,因此无法加上“半个 twip”,结果是只增加了 0 像素。
长话短说,影片并非无限地接近目标,但是它确实永远无法准确地到达目标点。这样一来,缓动代码就永远不会停止。我们要回答的问题是 “哪里才是物体最接近的目标位置?”,这需要确定到目标点的距离是否小于某个范围。我发现在很多软件中,如果物体与目标点的距离相差在一个像素以内,就可以说它已经到达了目标点,即可停止缓动了。