您的位置:首页 > 其它

(2012-01-08 旧博文搬运)[EssentialActionScript3.0中文版]无责任翻译-23章屏幕更新(2)

2016-04-09 03:04 417 查看


[EssentialActionScript3.0中文版]无责任翻译-23章屏幕更新(2)

空间

23.1.3. 指定的帧频VS实际的帧频

即使flash运行时根据帧频来表现预定屏幕更新,每秒真正能够完成的屏幕更新的数量 (即实际帧频) 常常低于程序员预设的帧频 (即指定帧频). 实际帧频很大程度上取决于电脑的运行速度,可用的系统资源,显示器的物理刷新率,以及flash运行时的上下文环境。因此,指定帧频可以看做一个速度上限。实际帧频不会超过这个限制,但是在一些情况下会低于它。

 

NOTE

Flash Player 无法总是达到指定帧频。要获得当前的指定帧频,我们检查Stage类的实例属性

frameRate. 比如,下面的类在一个文本框中显示指定帧频。

package {

import flash.display.*;

import flash.text.*;

public class ShowFrameRate extends Sprite {

public function ShowFrameRate () {

var t:TextField = new TextField();

t.autoSize = TextFieldAutoSize.LEFT;

t.text = stage.frameRate.toString();

addChild(t);

}

}

}

 

要获得实际帧频,我们使用Event.ENTER_FRAME 事件来测量flash运行时2次屏幕更新检查的间隔时间。Example 23-1 证明了这个技巧。我们将会在Chapter 24详细了解Event.ENTER_FRAME.

 

Example 23-1. 测定实际帧频(fps)

package 

{

         importflash.display.*;

         importflash.events.*;

         importflash.utils.*;

         importflash.text.*;

         publicclass FrameRateMeter extends Sprite

         {

                   privatevar lastFrameTime:Number;

                   privatevar output:TextField;

                   publicfunction FrameRateMeter()

                   {

                            output= new TextField();

                            output.autoSize= TextFieldAutoSize.LEFT;

                            output.border= true;

                            output.background= true;

                            output.selectable= false;

                            addChild(output);

                            addEventListener(Event.ENTER_FRAME,enterFrameListener);

                   }

                   privatefunction enterFrameListener(e:Event):void

                   {

                            varnow:Number = getTimer();  //getTimer返回返回初始化 Flash Player 后经过的毫秒数

                            varelapsed:Number = now - lastFrameTime;

                            var FPS:Number =Math.round(1000/ elapsed);

                            output.text= "Time since last frame: " +elapsed

                                        + "\nExtrapolatedactual frame rate: " + FPS

                                        + "\nDesignatedframe rate: " + stage.frameRate;

                            lastFrameTime= now;

                   }

         }

}

调试版本的flash运行时的实际帧频常常比发布版本的低很多。

 

 

23.2. 事件后屏幕更新

在前一节我们学习了既定屏幕更新是受到帧频的管理而间隔发生的。我们也学习了由事件侦听器引发的可视变化将等到下一个既定屏幕更新时刻到来才会渲染。在一个典型的24帧频中,侦听器的执行和它的可视输出的渲染之间的延迟是几乎察觉不到的。但是,对于由鼠标或键盘输入而引发的可视变化,即使微小的延迟也会使人感觉程序颤抖或者迟钝。于是,ActionScript 给了所有的鼠标和键盘事件的侦听器函数一个特殊的能力来调用一个事件后屏幕更新。事件后屏幕更新是一次紧跟随事件派送之后、在下一个预定更新到来之前的一次更新。

 

要在一个鼠标事件中请求一次事件后屏幕更新,我们在MouseEvent对象传递给任何侦听器函数的时候调用MouseEvent.updateAfterEvent()方法。比如,下面的代码就调用了一个事件后屏幕更新以响应一个MouseEvent.MOUSE_MOVE事件.

private function mouseMoveListener (e:MouseEvent):void {

e.updateAfterEvent();
// 触发更新

}

 

要在一个鼠标事件中请求一次事件后屏幕更新,我们在KeyboardEvent对象传递给任何侦听器函数的时候调用KeyboardEvent.updateAfterEvent()方法。比如,下面的代码就调用了一个事件后屏幕更新以响应一个KeyboardEvent.KEY_DOWN事件.

private function keyDownListener (e:KeyboardEvent):void {

e.updateAfterEvent();// 触发更新

}

 

在这2种情况下,调用updateAfterEvent()将引发flash运行时在事件派送后立刻更新屏幕,早于下一个既定屏幕更新。但是,即使事件后屏幕更新在下一个既定屏幕更新之前发生,它直到该事件派送的过程中的所有侦听器都执行完毕之前不会发生。

 

NOTE

与既定屏幕更新一样,FLASH不会为了执行事件后屏幕更新而打断一个代码块

有关updateAfterEvent()的实际应用可以看Chapter 22中的自定义鼠标指针类CustomMousePointer, 位于"找到鼠标指针的位置" 。CustomMousePointer 类绘制了一个蓝色三角的Sprite 来代替鼠标指针,然后使用 MouseEvent.MOUSE_MOVE事件侦听器来保持 Sprite跟随鼠标。在mouseMoveListener()方法中, updateAfterEvent()被用来引发事件后屏幕更新来保证指针动画顺畅,无论帧频是多少都可以。这里是CustomMousePointer类的mouseMoveListener()方法;注意黑体字的 updateAfterEvent()的调用。

 

private function mouseMoveListener(e:MouseEvent):void {

// 当鼠标移动,更新自定义指针的位置以符合系统鼠标指针的位置

var pointInParent:Point = parent.globalToLocal(newPoint(e.stageX, e.stageY));

x = pointInParent.x;

y = pointInParent.y;

// 请求一个事件后屏幕更新来保证动画尽可能顺畅

e.updateAfterEvent();

// 保证自定义指针是可见的(当系统指针离开FP可见区域的时候它可能隐藏)

if (!visible) {

visible = true;

}

}

注意当flash运行时更新屏幕以作为对updateAfterEvent(),的响应的时候,他不仅只渲染被侦听器触发的可视变化,还包括从最后一次屏幕更新到现在为止所有的可视变化。

 

23.2.1. Timer 事件的事件后屏幕更新

为了允许屏幕可以在任意的时间段后立刻更新,ActionScript 提供了TimerEvent.updateAfterEvent()方法,它强制在TimerEvent.TIMER事件后更新屏幕。

TimerEvent.updateAf
4000
terEvent() 方法是用在TimerEvent.TIMER事件侦听器函数内的,与键盘、鼠标的事件后更新的用法相同。

 

要证明TimerEvent.updateAfterEvent() 的使用,让我们创建一个夸张的例子,这个例子以比帧频快10倍的频率调用TimerEvent.TIMER 事件。我们开始先设置帧频为1帧/秒:

stage.frameRate = 1;

 

然后,我们创建一个Timer 对象来派送TimerEvent.TIMER事件,每100ms一次(一秒10次)。

var timer:Timer = new Timer(100, 0);

 

然后,我们为timer注册一个侦听TimerEvent.TIMER事件的侦听器器函数timerListener(), 如下:

timer.addEventListener(TimerEvent.TIMER, timerListener);

 

然后我们启动计时器:

timer.start();

 

在timerListener()函数内,我们绘制一个矩形并且把它放到屏幕上随即的位置。为了确保这个矩形在

TimerEvent.TIMER 事件派送完成后立刻显示出来(要早于下一次预定屏幕更新),我们使用

TimerEvent.updateAfterEvent() 来请求一个事件后屏幕更新。

这里是timerListener()的代码:

 

private function timerListener (e:TimerEvent):void{

// Create 矩形

var rect:Sprite = new Sprite();

rect.graphics.lineStyle(1);

rect.graphics.beginFill(0x0000FF);

rect.graphics.drawRect(0, 0, 150, 75);

rect.x =Math.floor(Math.random()*stage.stageWidth);

rect.y =Math.floor(Math.random()*stage.stageHeight);

// Add矩形to screen

addChild(rect);

// Request a post-event screen update

e.updateAfterEvent();

}

 

作为前面调用TimerEvent.updateAfterEvent() 的响应,timerListener() 中发生的可视改变会每100ms渲染一次,而不是1s一次。

 

作为参考 ,下面的代码在一个RandomRectangles类的环境中展示了我们前面的定时器方案.

 

package {

import flash.display.*;

import flash.events.*;

import flash.utils.*;

public class RandomRectangles extends Sprite {

public function RandomRectangles () {

stage.frameRate = 1;

var timer:Timer = new Timer(100,0);

timer.start();

timer.addEventListener(TimerEvent.TIMER,timerListener);

}

private function timerListener (e:TimerEvent):void {

var rect:Sprite = new Sprite();

rect.graphics.lineStyle(1);

rect.graphics.beginFill(0x0000FF);

rect.graphics.drawRect(0, 0, 150, 75);

rect.x = Math.floor(Math.random()*stage.stageWidth);

rect.y = Math.floor(Math.random()*stage.stageHeight);

addChild(rect);

e.updateAfterEvent()

}

}

}

在 Chapter 24, 我们将继续学习Timer 类,用它来创建动作和其他形式的动画。

NOTE

ActionScript 2.0的setInterval()也可以使用updateAfterEvent() 来调用事件后屏幕更新,但是使用

flash.utils.Timer比setInterval()好,因为它提供了启动或停止定时事件,且告知数个侦听器该定时事件的发生。考虑避免在ActionScript3.0使用setInterval()。

 

23.2.2. 自动发生的事件后屏幕更新

在 Flash Player 9, 某个按钮式样的继承自Sprite 的交互元件将调用一个自动式的事件后更新(就好像在程序中调用了updateAfterEvent())。特别是下面的这些交互元件将会自动调用事件后更新:

• 将鼠标移上或是移离一个继承自Sprite的类的实例

• 在一个继承Sprite的实例上按下或松开鼠标左键

• 使用空格键或回车键激活一个继承Sprite的实例上它

 
在未来版本的Flash Player, 也许有可能这个自动发生的屏幕更新行为可能会只适用于

SimpleButton对象。 因此,你最好避免在你的代码中依赖它。

 

 

23.3. 重绘区域

正如我们之前在"预制屏幕更新"中学习的,Flash运行时只在需要的时候更新屏幕(即是说,当可视内容被改变或者添加)。更明确地说,当Flash运行时更新屏幕的时候,它只会渲染那些比较最后一次更新的时候发生了改变的区域。比如,假设一个动画有2帧,第一帧包含了一个圈、第二帧包含了一个同样的圈外加一个矩形。当Flash运行时渲染第二帧的时候,他重绘一个矩形区域来显示这个矩形,但是并不重绘圆。这个矩形区域包含了所有被改变了的内容,称作重绘区域 (有时在图形程序中被叫做dirty rectangle).

脏矩形技术(DirtyRectangle)

  在2D游戏中,每次更新屏幕,都将会将整个屏幕上的图像重新绘制一遍,而更新的内容往往不是很多,甚至只是一个小区域,强制重绘带来了很大的资源浪费,尤其是在一些休闲游戏、桌面游戏中体现明显。脏矩形技术正是利用只更新变化区域来达到提高引擎效率的目的。[1]在脏矩形系统中,屏幕上更新的区域被称为“脏矩形”,引擎仅仅将脏矩形部分重绘,而其他部分保持原样。

NOTE

在调试版本的Flash运行时,可以通过右击播放器窗口选择“显示重绘区域”来显示重绘框

 

 

收藏于 2012-01-08
来自于百度空间
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: