`
wgcode
  • 浏览: 601699 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Flash定时器

阅读更多

基于计时器的动画 

     作为计时器动画使用的关键类,不出意料,它就是 flash.utils.Timer。同时我们还需要 

flash.events.TimerEvent  类。 

     使用计时器实际上与使用 enterFrame  没什么两样。只需要我们去创建一个计时器

(Timer),告诉它多久“滴答响”一声,并侦听 TimerEvent.TIMER  事件,就像对 

Event.ENTER_FRAME  事件的侦听一样。哦,还要告诉计时器何时开始!接下来,计时器

就会每隔一段时间广播一个计时事件,它将调用赋给它的函数进行处理。计时器触发的间隔

 

以毫秒为单位,在创建该计时器时指定。让我们来看一个简单的例子(可在 Timer1.as  中找

到): 

package { 

 import flash.display.Sprite; 

 import flash.utils.Timer; 

 import flash.events.TimerEvent; 

  public class Timer1 extends Sprite { 

    private var timer:Timer; 

    public function Timer1() { 

   init(); 

  } 

    private function init():void { 

   timer = new Timer(30); 

   timer.addEventListener(TimerEvent.TIMER, onTimer); 

   timer.start(); 

  } 

    private function onTimer(timer:TimerEvent):void { 

   trace("timer!"); 

  } 

 } 

} 
 重要的部分加粗表示。我们创建一个计时器,告诉它每隔 30  毫秒触发一次,意味着每秒约 

33  次。添加一个事件的侦听器并将它起动。 onTimer  方法与我们以前用的 onEnterFrame 

类似。 

     这是我们所要知道计时器的大部分内容。它还有其它两个漂亮的特征。一个是在创建计

时器时,可以通过第二个参数,repeatCount,告诉它运行的次数。假设我们要让计时器每秒

运行一次,总共执行 5 秒。就可以这样做: 

    timer = new Timer(1000, 5); 

如果没有指定重复的次数,或传入 0,那么计时器将无限地运行。 

     另一个好东西是可以让计时器在某个点上启动或停止,只需要调用 timer.stop  或 

timer.start  即可。在某些例子中,这样做比删除和重新加入事件侦听器更简单一些。 

     与 enterFrame  相比,很多朋友更喜欢使用计时器的原因是,理论上讲,计时器可以让

我们控制动画的速度——这是对于帧的不精确性的一个重大改进。我之所以说“理论上讲”,

是因为这里有些事情需要弄清楚。 

     首先,实际上计时器要依赖于帧频。另一个原因是计时器的事件函数中的代码会增加整

个计时器间隔。稍后我会解释一下第二点。现在,让我们看看计时器是如何与帧频相关联的。

下面是文档类 Timer2.as,使用到我们著名的 Ball  类。

package { 

 import flash.display.Sprite; 

 import flash.utils.Timer; 

 import flash.events.TimerEvent; 

  public class Timer2 extends Sprite { 

    private var timer:Timer; 

    private var ball:Ball; 

    public function Timer2() { 

   init(); 

  } 

    private function init():void { 

   stage.frameRate = 1;   340

   ball = new Ball(); 

      ball.y = stage.stageHeight / 2; 

   ball.vx = 5; 

   addChild(ball); 

   timer = new Timer(20); 

   timer.addEventListener(TimerEvent.TIMER, onTimer); 

   timer.start(); 

  } 

    private function onTimer(event:TimerEvent):void { 

   ball.x += ball.vx; 

  } 

 } 

} 
 这里我们把创建出来的小球放在舞台的左侧。让它以 vx 为 5  的速度穿过舞台。然后设置

一个 20  毫秒的计时器,每秒约调用 50  次。同时设置影片的帧频为 1  就是为了看看帧频

是否会对计时器有影响。 

     测试后,我们会看到小球没有平稳地穿过屏幕,而是每秒钟跳一下  ——  以帧的频率。

每跳一次都会大于 5  像素。为什么呢? 

     回想一下一、二章的动画基础,我们知道模型是需要更新的,所以屏幕要根据新的模型

被刷新。这里时间间隔函数确实将更新了模型并将小球每次移动 5  像素,但是只有在 Flash 

进入新的一帧时才进行刷新。仅仅运行一个函数不会驱使 Flash  进行重绘。 

     幸运的是,Macromedia (现在的 Adobe)  的好人们看到了这个问题并给了我们另一个小

工具:updateAfterEvent。最初是在 Flash MX  中介绍的,现在它是传给计时器事件函数中 

TimerEvent  对象的一个方法。就像它的名字一样,在事件之后刷新屏幕的。当然,由于它

是 TimerEvent  类的一个方法,所以只有在收到一个事件后才能被调用。(事实上,它也是 

KeyboardEvent  和 MouseEvent  的方法,因此也能在这些处理函数中调用。) 

这样一来,我们可以修正一下 onTimer  事件: 

private function onTimer(event:TimerEvent):void { 

  ball.x += ball.vx; 

 event.updateAfterEvent(); 

} 
 现在一切有所好转了。非常流畅。但是如果您意识到小球应该每秒更新 50  次,我们看到的

基本上应该是一个 50 fps  的动画。这就意味着小球的运动应该比第四章创建的 fps  小于 

50  的 enterFrame  事件的例子更为流畅。但是实际的运动更为缓慢。 

     问题出来了,计时器在某种程度上要依赖于帧频。通过我的测算,在帧频为 1 fps  时,

我们所得到的计时器运行的最快间隔大约为 100  毫秒。 

     我已经听到了嘲笑:每帧只得到了 10  次间隔。所以,试将帧频改为 5。它允许每秒更

新 50  次。在我看来,仍然不是很流畅。如果不大于每秒 10  帧的话是不会达到真正流畅的

效果。因此,我们可以看到使用计时器并不能完全让我们从帧频的铐链中解脱出来。 

     下一个问题是计时器内部是怎样工作的,它会对计时的精确度产生多大的影响。当 

timer.start()  被调时,实际上发生了什么,Flash 等待一段指定的时间,然后广播事件,运行

与该计时器相关的处理函数。只有当函数执行完成后计时器才开始定时下一次计时。看一个

例子,假设我们有一个每 20  毫秒运行一次计时器。假设在处理函数中有大量的代码需要执

行 30  毫秒。下一轮定时只有在所有的代码都运行完成后才开始。这样一来,我们的函数会

在大约每 50  毫秒调用一次。因为在用户的机器上没法精确地知道代码会运行多快,所以多

数情况下,计时器动画不会比帧动画精确多少。 

    如果您需要真正的精确,那么基于时间的动画则是我们的必经之路。 

    341

基于时间的动画 

     如果要让动画中物体的速度是一致的,那么基于时间的动画就是我们要使用的方法。这

种方法在一些游戏中比较常用。我们知道,帧和计时器动画都不能以特定的速率播放。一个

复杂的动画在一台又老又慢的电脑上运行可能要比最初设计的速度慢上许多。我们马上会看

到,使用基于时间的动画无论最终动画运行的帧频如何,都将获得可靠的速度。 

     首先要改变考虑速度的方法。到目前为止,在我说 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;   342

      } 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。虽然没有机器能够

与真正的帧频相吻合,但是基于时间的动画将保证每个人看到的影片运行得都是最流畅

分享到:
评论

相关推荐

    uCOS-II.rar_ucos flash

    本资料包“uCOS-II.rar_ucos flash”主要探讨了如何在三星ARM芯片上实现和优化uCOS-II,涵盖了内存管理、Flash定时器以及库函数等关键环节。 一、uCOS-II操作系统基础 uCOS-II是由Micrium公司开发的一款抢占式实时...

    S7-1200 关断延时定时器-跟我学 FLASH视频.rar

    本资源"《S7-1200 关断延时定时器-跟我学 FLASH视频》"是一个专门针对S7-1200 PLC的关断延时定时器操作教程,通过FLASH视频的形式,以直观、生动的方式教授这一关键功能。 关断延时定时器(也称为OFF delay timer)...

    mini2440定时器中断

    在烧录到nand_flash的过程中,定时器中断可能用于控制程序的加载时间,确保在特定时间点执行特定的操作,或者在系统启动后初始化必要的硬件资源。nand_flash作为非易失性存储器,通常用于存储操作系统映像和应用程序...

    S7-1200 脉冲定时器-跟我学 FLASH视频.rar

    本教程通过"跟我学"的FLASH视频形式,深入浅出地讲解了如何在S7-1200中运用脉冲定时器。 首先,我们要了解S7-1200中的脉冲定时器类型。S7-1200支持两种类型的脉冲定时器:PTO(Pulse Timer Output)和PTU(Pulse ...

    S7-1200 保持型接通延时定时器-跟我学 FLASH视频.rar

    本资源"《S7-1200 保持型接通延时定时器-跟我学 FLASH视频.rar》"是一个关于如何在S7-1200 PLC中使用保持型接通延时定时器的教程,通过Flash动画的形式,深入浅出地讲解了这一重要功能。 保持型接通延时定时器(PTO...

    C51 定时器

    C8051F020是一款高速、低功耗、增强型的8051单片机,具有内置Flash存储器和多种外设接口。ZLG7289则是一种专门的串行LCD控制器,常用于实现单片机与LCD显示器的数据通信。在C8051F020中集成ZLG7289的驱动代码,可以...

    Arduino之TimerOne定时器库

    在这个例子中,当定时器溢出时,`flashLED()`函数会被调用,从而实现LED的周期性闪烁。 **六、总结** TimerOne库是Arduino平台上一个强大的定时工具,它通过更灵活的配置和中断机制,极大地扩展了Arduino的定时...

    STM32如何设置定时器

    如果程序在RAM中运行,中断向量表需设置在0x20000000,否则在Flash中设置为0x08000000。`NVIC_SetVectorTable()`函数完成此任务。 6. **编写中断服务函数**: 当定时器中断发生时,会跳转到指定的中断服务函数。...

    nios实验工程,里面含有flash,PIO,sdram,定时器,外部中断等模块

    在本文中,我们将深入探讨基于 Altera Nios II 的 FPGA 实验工程,它包含了多个关键模块,如 Flash、PIO(可编程输入/输出)、SDRAM、定时器以及外部中断。这些组件是嵌入式系统设计中的核心部分,尤其是在 FPGA ...

    基于51单片机的定时器

    选择AT89C51作为主控芯片,因为它拥有4KB的Flash存储空间,8KB的程序运行内存,4个8位I/O口,足够满足定时器的控制需求。 2.4 复位电路 复位电路是保证单片机正常工作的关键部分,一般采用上电复位和手动复位相结合...

    单片机定时器程序,可以直接烧录

    6. **烧录与调试**:程序编写完成后,需要通过编程器将程序烧录到单片机的Flash存储器中。之后,可能需要借助仿真器或调试器进行运行测试,观察并调整程序行为。 这个压缩包提供的源代码是一个很好的学习和实践平台...

    stm32F10x单片机通用定时器库函数配置

    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0000); NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_...

    stm32l151c8t6-A单片机关于定时器的时钟配置和计算(定时1ms的配置).pdf

    - 配置FLASH的读取访问时间、预取缓冲器和延迟周期,以匹配系统时钟频率。 - 设置HCLK(AHB总线时钟)分频值为1。 - 配置PLL参数,包括时钟源选择、倍频因子和分频因子,并启动PLL。 - 当PLL稳定后,将其作为...

    LPC210X 定时器使用方法

    这些微控制器配备了丰富的内部资源,如8K/16K/32K字节的FLASH存储器、2K/4K/8K字节的SRAM以及多种外围设备,如硬件I2C、SPI、PWM等。LPC210X系列特别适合于需要高速运行和低功耗的应用场景。 #### 二、LPC210X ...

    定时器方式0工作原理

    定时器工作方式0工作原理Flash动画,形象、直观,方便理解。

    利用定时器和蜂鸣器唱歌

    使用编程器或者调试器,可以将这段代码下载到单片机的Flash存储器中执行。 通过这个项目,我们可以学习到如何使用单片机的定时器资源,理解数字信号如何转换为模拟声音,以及如何用C语言编写单片机控制程序。同时,...

    swf版的计时器和定时器

    本主题聚焦于SWF版的计时器和定时器,这是一种基于Flash技术的实现方式。下面将详细介绍这两个概念以及它们在实际应用中的重要性。 计时器(Timer)与定时器(Timer)在编程中通常指的是能够执行周期性任务的组件。...

    【STM32】标准库-通用定时器-外部时钟模式2

    采用STM32F429IGT6单片机,KeilMDK5.32版本 使用SysTick系统滴答定时器进行延时 LED_R、LED_G、LED_B分别为PH10,PH11,PH12 Key1为PA0,Key2为PC13 使用通用定时器4,定时器时钟为外部时钟...KEIL5下载配置有FLASH与SRAM

    【STM32】标准库-通用定时器-PWM输出比较-呼吸灯

    采用STM32F429IGT6单片机,KeilMDK5.32版本 使用SysTick系统滴答定时器进行延时 LED_R、LED_G、LED_B分别为PH10,PH11,PH12 使用通用定时器3,定时器时钟频率为90MHz,预分频器值为9000 - ...KEIL5下载配置有FLASH与SRAM

    基于DS12C887的通用定时器设计

    - **程序存储**: 内部集成4KB Flash ROM,用于存储程序代码。 - **数据存储**: 256B的RAM用于存储运行时数据。 ##### 3. 移位寄存器74LS164 - **串行至并行转换**: 74LS164是一种串行输入、并行输出的移位寄存器,...

Global site tag (gtag.js) - Google Analytics