加载中…
个人资料
小杨柿子技术
小杨柿子技术
  • 博客等级:
  • 博客积分:0
  • 博客访问:321,192
  • 关注人气:230
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

第八章  缓动与弹性运动Ⅱ [FL车在臣]

(2008-04-30 21:00:41)
标签:

弹性运动

一维弹性运动

二维弹性运动

鼠标弹簧

actionscript

分类: Making Things Move!

弹性运动
    一直以来,我都认为弹性运动将是 ActionScript 动画中最强大和最有用的物理学概念。几乎所有的物体都可以使用弹性运动。下面就来看看什么是弹性运动以及在 Flash 编程中的应用。
    如同本章开始时所提到的,弹性的加速度与物体到目标点的距离成正比例。想象一下现实中弹簧的性质。把一个小球拴在橡皮圈一头,再将另一头系在一个固定的地方。当小球悬在半空时,在没有施加外力的情况下,小球就处在目标点的位置上。再将小球微微拉动,松手后橡皮圈会对其施加一些外力,又将小球拽回了目标点。如果用最大力量将小球挪远,那么橡皮圈就会对小球施加很大的力。小球急速向目标点飞去,并朝着另一面运动。这时,小球的速度非常快。当它越过了目标点时,橡皮圈开始把它向回拉——改变其速度向量。这时,小球会继续运动,但是它运动得越远,所受到的拉力就越大。然后,速度向量为零,方向相反,一切再重新开始。最终,在反弹了几次后,速度逐渐慢下来直到停止——停在目标点上。
    下面我们将这个过程翻译成 ActionScript。为了简化这个过程,我们先在一维坐标上进行实验。

 

一维坐标上的弹性运动
    这里我们仍然使用可以拖拽的小球作为主体。默认位置还是 x 轴的 0 点,使它具有运动到中心点的弹性。像使用缓动一样,需要一个变量保存弹性的数值。可以认为这个数同距离的比例,较大的弹性值会使弹性运动显得十分僵硬。较小的弹性值会使弹性运动像一条松紧带。我们选用 0.1 作为弹性 (spring) :
private var spring:Number = 0.1;
private var targetX:Number = stage.stageWidth / 2;
private var vx:Number = 0;

不要担心物体当前的位置,只需要知道如何确定这些变量与表达式就可以了。
然后加入运动代码并且找出与目标点的距离:
var dx:Number = targetX - ball.x;

下面计算加速度。加速度与距离成正比,也就是距离乘以 spring 的值:
var ax:Number = dx * spring;

得到了加速度以后,我们就回到了熟悉的地方,把加速度加到速度向量中。
vx += ax;
ball.x += vx;
    在写代码前,先来模拟一下运行时的数据。假设物体的 x 坐标为 0, vx 为 0,目标 x 为 100,spring 值为 0.1。执行过程如下:
1. 距离(100) 乘以 spring,得到 10。将它加入 vx 中,此时 vx 变为 10。再将 vx 加入到速度向量上使得 x 位置变为 10。
2. 下一次,距离(100-10) 等于 90。加速度为 90 乘以 0.1,结果为 9。将结果加入 vx ,使 vx 变为 19。 x 坐标变为 29。
3. 下一次,距离为 71,加速度为 7.1,将结果加到 vx 中,使 vx 变成 26.1。 x 坐标变为 55.1。
4. 下一次,距离为 44.9,加速度为 4.49, vx 变成 30.59。 x 坐标变为 85.69。
    注意,每次的加速度随着物体越接近目标,变得越来越小,但是速度向量仍在不断增涨。虽然涨幅不像启初那样快,但是速度却越来越快。
    几次过后,物体就超过了目标点,到达了 117 的位置。现在的距离是 100 – 117,等于 -17。将这一部分加入到速度向量中,会使物体的移动稍稍慢下来。
    现在大家知道弹性是如何工作了吧,让我们来实践一下。与往常一样,要保证 Ball 类是有效的,使用下面这个文档类(Spring.as):
package {
 import flash.display.Sprite;
 import flash.events.Event;
 public class Spring1 extends Sprite {
  private var ball:Ball;
  private var spring:Number = 0.1;
  private var targetX:Number = stage.stageWidth / 2;
  private var vx:Number = 0;

  public function Spring1() {
   init();
  }
  private function init():void {
   ball = new Ball();
   addChild(ball);
   ball.y = stage.stageHeight / 2;
   addEventListener(Event.ENTER_FRAME, onEnterFrame);
  }
  private function onEnterFrame(event:Event):void {
   var dx:Number = targetX - ball.x;
   var ax:Number = dx * spring;
   vx += ax;
   ball.x += vx;

  }
 }
}
    试验一下,可以看出一个类似于弹簧的效果,唯一的问题是它永远不会停止。前面在描述弹性运动时说过“速度逐渐慢下来直到停止”。由于小球每次摇摆时的距离相同,所以速度向量也相同,这样它就会以同样的速度来回摆动。这时,我们需要引入摩擦力。非常简单——只需要一个 friction 变量,值为 0.95。放在类开始的地方作为成员变量:

private var friction:Number = 0.95;
在 enterFrame 函数中,每次将 vx 乘以 friction,就可以了。
文档类 Spring2.as 的 onEnterFrame 方法如下:
private function onEnterFrame(event:Event):void {
    var dx:Number = targetX - ball.x;
    var ax:Number = dx * spring;
    vx += ax;
    vx *= friction;
    ball.x += vx;
}
 这样一来,程序就完整了,虽说只是个一维的弹性运动。试改变 friction 的值观察运动效果。认真理解这个程序会对大家非常有帮助。掌握这个程序后,就来看看二维的弹性运动吧。

 

二维弹性运动
 好了,不用麻烦了,直接看程序(Spring3.as):
package {
 import flash.display.Sprite;
 import flash.events.Event;
 public class Spring3 extends Sprite {
  private var ball:Ball;
  private var spring:Number = 0.1;
  private var targetX:Number = stage.stageWidth / 2;
  private var targetY:Number = stage.stageHeight / 2;
  private var vx:Number = 0;
  private var vy:Number = 0;
  private var friction:Number = 0.95;
  public function Spring3() {
   init();
  }
  private function init():void {
   ball = new Ball();
   addChild(ball);
   addEventListener(Event.ENTER_FRAME, onEnterFrame);
  }
  private function onEnterFrame(event:Event):void {
   var dx:Number = targetX - ball.x;
   var dy:Number = targetY - ball.y;
   var ax:Number = dx * spring;
   var ay:Number = dy * spring;
   vx += ax;
   vy += ay;
   vx *= friction;
   vy *= friction;
   ball.x += vx;
   ball.y += vy;
  }
 }
}
    我们看到,唯一不同之处就是加入了 y 轴的运动。但问题是,这个效果看上去还是很像一维的弹性运动。是的,虽然小球是沿着 x,y 轴运动,但它仍是直线运动。这是因为加速度的起点均为零,并且两种力的大小相同,因此是直线运动到目标点。
    为了让效果更好,将初始 vx 的值设置得大一些,比如 50。现在,看起来更加形象、真实了。但这只是个开始,更厉害的还在后面呢。

 

向移动目标运动
    实现弹性运动并不需要目标点是固定。前面在介绍缓动运动时,我们就介绍了一个非常简便快捷的方法——小球跟随鼠标。要让小球跟随鼠标位置非常简单,只要将原来的 targetX 和 targetY 变成鼠标位置即可。在弹性运动中也是如此,每一帧都要计算物体与目标点的距离,然后再确定加速度。
    效果非常 Cool,我认为值得大家多写几遍。事实上,代码的变化并不大,只需将前面的程序做如下修改:
var dx:Number = targetX - ball.x;
var dy:Number = targetY - ball.y;
改为:
var dx:Number = mouseX - ball.x;
var dy:Number = mouseY - ball.y;
    设置完成后,就可以将 targetX 和 targetY 这两个变量声明删除。如果不删,也不会有什么问题。

 

弹簧在哪?
    下面我们将看到小球在橡皮圈上运动的情况。但是似乎还需要一个可见的橡皮圈,只需要用绘图 API 绘制一条线即可!绘图指令可以直接写在 Sprite 的子类中。在很多复杂的程序中,我们可能需要单独创建一个空影片当作绘图层来用。
    方法很简单。在确定了小球的位置后,调用 clear() 将之前的线条擦除。然后重新设置 lineStyle 并绘制出小球与鼠标的连线。我们只需要在 enterFrame 函数中执行如下操作:
graphics.clear();
graphics.lineStyle(1);
graphics.moveTo(ball.x, ball.y);
graphics.lineTo(mouseX, mouseY);
    非常有趣!我们还能做什么?再加上重力怎么样?这样小球看上去更像是悬在空中。很简单,只需要在每帧的 vy 中加入重力(gravity)。以下代码结合了重力与画线指令(Spring5.as):
package {
 import flash.display.Sprite;
 import flash.events.Event;
 public class Spring5 extends Sprite {
  private var ball:Ball;
  private var spring:Number = 0.1;
  private var vx:Number = 0;
  private var vy:Number = 0;
  private var friction:Number = 0.95;
  private var gravity:Number = 5;
  public function Spring5() {
   init();
  }
  private function init():void {
   ball = new Ball();
   addChild(ball);
   addEventListener(Event.ENTER_FRAME, onEnterFrame);
  }
  private function onEnterFrame(event:Event):void {
   var dx:Number = mouseX - ball.x;
   var dy:Number = mouseY - ball.y;
   var ax:Number = dx * spring;
   var ay:Number = dy * spring;
   vx += ax;
   vy += ay;
   vy += gravity;
   vx *= friction;
   vy *= friction;
   ball.x += vx;
   ball.y += vy;
   graphics.clear();
   graphics.lineStyle(1);
   graphics.moveTo(ball.x, ball.y);
   graphics.lineTo(mouseX, mouseY);

  }
 }
}
    执行后的结果如图 8-2 所示。请注意,我们加入的重力 (gravity) 只有 5,只是为了让小球下坠。如果重力太小的话,就看不到效果了。
第八章 <wbr> <wbr>缓动与弹性运动Ⅱ <wbr>[FL车在臣]
图8-2 可见的鼠标弹簧
    我们刚刚又违背了真实的物理学。当然,不能在物体上施加“累积重力”!重力是一个常数,取决于物体所在星球的大小和质量。我们所能做的就是累加物体的质量,以便在物体上产生多个重力。因此,严格来讲,重力还应该是 0.5,而质量应该在 10 左右。接下来,用质量乘以重力等于 5。或者可将 gravity 变量名改为 forceThatGravityIsExertingOnThisObjectBasedOnItsMass。好了,大家明白这个意思后我就可以节省一下空间使用变量名 gravity。
    同样,试验一下这个程序。试减少 gravity 与 spring 的值,试改变 friction 的值。我们可以有无限多种数字的组合,可以建立出任何类型的重力系统。

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有