Flash实用技巧1--基于时间的动画(as3.0)

发布时间:2012-11-30    发布:    分类:技术文档

      如果要让动画中物体的速度是一致的,    那么基于时间的动画就是我们要使用的方法。 
种方法在一些游戏中比较常用。我们知道,帧和计时器动画都不能以特定的速率播放。一个
复杂的动画在一台又老又慢的电脑上运行可能要比最初设计的速度慢上许多。       我们马上会看
到,使用基于时间的动画无论最终动画运行的帧频如何,都将获得可靠的速度。
      首先要改变考虑速度的方法。到目前为止,在我说 vx = 5 时,我们使用的单位是像素
每帧(pixels per frame)  。换句话讲,每进入新的一帧物体都将在 x 轴上运动 5 像素。在计
时器动画中,当然,就应该是每次定时间隔移动 5 像素。
      对于时间动画,我们将使用真正的时间单位,如秒。由于我们是处理完整的一秒,而非
其中的一部分,因此这个速度值就要更大一些。如果某个物体的速度是每帧 10 像素,每秒
30 帧的速度运动,     大约每秒 300 像素。 比如下面这个例子,我从第六章的 Bouncing2.as 文
档类中截取了一部分并进行了一些变化,见下面粗体部分(也可在 TimeBased.as 中找到)     
package {
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.utils.getTimer;
  public class TimeBased extends Sprite {
   private var ball:Ball;
   private var vx:Number;
   private var vy:Number;
   private var bounce:Number = -0.7;
   private var time:Number;
   public function TimeBased() {
    init();
}
private function init():void {
  stage.frameRate = 10;
  ball = new Ball();
  ball.x = stage.stageWidth / 2;
  ball.y = stage.stageHeight / 2;
  vx = 300;
  vy = -300;
  addChild(ball);
  time = getTimer();
  addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void {
  var elapsed:Number = getTimer() - time;
  time = getTimer();
  ball.x += vx * elapsed / 1000;
  ball.y += vy * elapsed / 1000;
  var left:Number = 0;
var right:Number = stage.stageWidth;
var top:Number = 0;
var bottom:Number = stage.stageHeight;
if (ball.x + ball.radius > right) {
  ball.x = right - ball.radius;
  vx *= bounce;
      } else if (ball.x - ball.radius < left) {
        ball.x = left + ball.radius;
        vx *= bounce;
      }
      if (ball.y + ball.radius > bottom) {
        ball.y = bottom - ball.radius;
        vy *= bounce;
      } else if (ball.y - ball.radius < top) {
        ball.y = top + ball.radius;
        vy *= bounce;
      }
    }
  }
}
如上所描述,我改变了对速度的计算,让它们使用固定的值,而非随机值。然后我创建了一
个名为 time 的变量,让它等于 flash.utils.getTimer 函数的结果。getTimer 函数非常简单。
它返回影片已经运行了的毫秒数 —— 这就是它全部的工作。我们没有办法清除它,重启它,
改变它,等等。它只是一个计数器。
        看起来它似乎用处不大,但是如果先调用一次 getTimer 将值保存起来,稍后再调用它
一次,将两个结果相减,我们就能知道确切的—— 毫秒 ——这两次调用之间经过了多少时
间。
        这就是策略:在每帧的开始时调用 getTimer 计算与上一帧间隔了多长时间。如果将它
除以 1,000,我们将得到以秒为单位的间隔时间,这是个以秒为单位的分数。由于我们的 vx
和 vy 现在是以像素每秒来计算的,因此可以让它们去乘以这个分数,这样就知道要对物体
移动多少了。同样,不要忘记重新设置 time 变量的值,以便让下一帧进行计算。
     测试一下,  我们将看到小球移动的速度几乎与最初的速度相同!但是真正令人激动的是
我们可以以任何帧频来发布这个影片,它仍然可以以同样的速度运动!通过修改
stage.frameRate 的值,试验一下高到 1,000 fps,低到 10 fps,你会看到小球的速度是相同
的。当然,较高的频率会让动画更加流畅,而较低的频率则会十分不连贯,但是速度是一致
的。
     大家可以把这个技术应用在本书任何一个包含速度的例子中。  如果这样的话, 还需要将
相似的技术应用在加速度或外力上,如重力,因为它们也是基于时间的。加速度肯定要比转
前要大很多,因为加速度被定义为速度对时间的变化率。例如,重力大约为 32 英尺/秒/
秒。
     如果在一个 30 fps 帧的动画中,重力为 0.5 的话,那么现在就应该是 450。计算方法
0.5 * 30 * 30。然后像这样将它加入:
       vy += gravity * elapsed / 1000;
在最后一个例子中加入 450 重力后测试一下。我们会看到它与帧动画中加入重力 0.5 的效
果是相同的。使用这种技术的一个技巧是将帧频设置得非常高,如 100。虽然没有机器能够
与真正的帧频相吻合,但是基于时间的动画将保证每个人看到的影片运行得都是最流畅的。
同质量物体的碰撞
    回忆一下第十一章的动量守恒。那里有非常严谨的代码。不过,当两个相同质量的物体
发生碰撞时,我们实现起来可以更简单一些。基本原理是,两个物体沿着碰撞的线路交换它
们的速度。同时还要用坐标旋转来决定碰撞的线路,以及物体的速度,这样就摆脱了复杂的
动量守恒公式。来看看它是如何工作的,让我们回到文件 MultiBilliard2.as 中,将用它作为
下一个例子 SameMass.as 的基础。我就不再列出原先所有的代码了,因为它实在是一个很
大的文件。但是,我们要来看一下创建所有小球的 for 循环:
for(var i:uint = 0; i < numBalls; i++) {
var radius:Number = Math.random() * 50 + 20;
  var ball:Ball = new Ball(radius);
  ball.mass = radius;
  ball.x = Math.random() * stage.stageWidth;
  ball.y = Math.random() * stage.stageHeight;
  ball.vx = Math.random() * 10 - 5;
  ball.vy = Math.random() * 10 - 5;
  addChild(ball);
  balls.push(ball);
}
对于新的文件来说,要把粗体字的部分改为这一行:
      var radius:Number = 30;
让所有小球大小都相同,消除了质量的概念,相当于给它们相同的质量。
接下来,看一下 checkCollision 函数。请找到这一部分:
// 旋转 ball0 的速度
var vel0:Point = rotate(ball0.vx,
ball0.vy,
sin,
cos,
true);
// 旋转 ball1 的速度
var vel1:Point = rotate(ball1.vx,
ball1.vy,
sin,
cos,
true);
// 碰撞反应
var vxTotal:Number = vel0.x - vel1.x;
vel0.x = ((ball0.mass - ball1.mass) * vel0.x +
2 * ball1.mass * vel1.x) /
(ball0.mass + ball1.mass);
vel1.x = vxTotal + vel0.x;
这一部分找出了碰撞线路上的速度,根据物体的质量求出碰撞的结果。“碰撞反应”部分是
动量守恒的要素,这就是我们可以消除的部分。我们可以让 vel0 和 vel1 进行交换,就可
以很容易地替换它了。整个代码段如下:
// 旋转 ball0 的速度
var vel0:Point = rotate(ball0.vx,
ball0.vy,
sin,
cos,
true);
// 旋转 ball1 的速度
var vel1:Point = rotate(ball1.vx,
ball1.vy,
sin,
cos,
true);
// 交换两个速度
var temp:Point = vel0;
vel0 = vel1;
vel1 = temp;
这里甚至还可以再优化, 但是为了代码的清晰我就不做改变了。现在我们已经摆脱了一小块
儿数学问题,测试一下修改前与修改后的文件,所得的结果是相同的。
 

  

查看 [2752]   评论 [0] 
相关标签: 网页设计  视觉设计 
文章评论
暂无数据!
我来说两句
昵 称:
评 论:
   
咨询电话:020-61136292 87569708 61004412 61004413
讯博官网 | 走进讯博 | 整合营销 | 案例解读 | 资讯中心 | 案例欣赏 | 产品体验区 | 客户如是说 | 联系我们
版权所有 © 2003-2014 广州讯博网络科技有限公司 粤ICP备08107356号 开心一刻
Website Design & Power by:Cenbel.com