走在网页游戏开发的路上(六)

Flash动画原理

——动画是将静止的画面变为动态的艺术.实现由静止到动态,主要是靠人眼的视觉残留效应.利用人的这种视觉生理特性可制作出具有高度想象力和表现力的动画影片.

0.  前言

像所有的动画显示一样,Flash的动画原理也是通过不断的刷新屏幕,利用每次屏幕上显示对象位置的不同、大小色彩的变化等产生动画效果。动画编程的关键是一定要有变化,而且该变化需要在一定时间内来完成(以达到欺骗人眼,使分解的画面连续起来,达到运动的效果)。Flash中使用帧频来控制每秒钟刷新屏幕的次数,通过使用的帧频的范围在12~60帧每秒,推荐使用的是24帧每秒这样的一个速度。

ActionScript 3.0的动画编程也是同样的原理,通过不断的刷新屏幕来实现动画效果。ActionScript 3.0的动画编程按照实现的方式可以分为两种:

F  对显示对象的显示属性进行控制,调整每次刷新屏幕时显示对象的显示属性实现动画效果,这种称为显示属性动画

F  利用绘制API在每帧中使用代码绘制不同的形状,从而产生的动画效果,这种称为代码绘制动画

通过编程实现刷新屏幕,ActionScript 3.0中提供了两种方式可供选择:

F  帧循环更新:利用Flash本身的帧频速度,在每次刷新屏幕时改变显示对象。此方法需要使用事件侦听器侦听显示对象的Event.ENTER_FRAME事件。

F  定时器更新:利用Timer类的定时更新功能,每隔一定的事件使显示对象改变一次。此方法需要使用事件侦听器侦听显示对象的TimerEvent.TIMER事件。

下面具体介绍帧循环更新、定时器更新实现动画效果,和它们的差异及选择。

1.  Event.ENTER_FRAME事件做动画的原理

每当Flash运行器执行一次预定屏幕更新检查的时候它调度Event.ENTER_FRAME事件。注册以接收Event.ENTER_FRAME通知的任何函数都被反复执行,在由当前Flash运行器帧速率决定的一个频率下。由任何Event.ENTER_FRAME事件监听器做出的可见变化在它退出之前被描绘,这就是Event.ENTER_FRAME做动画的原理。

Event.ENTER_FRAME事件做动画的缺陷

每当想要改变指定的帧速率的时候,我们必须更新基于该帧速率计算速度的所有代码(除非使用基于速度的动画)

Flash运行器不总是能到达指定的帧速率,动画变慢。这种变慢甚至因系统负载而不同,帧速率可能只在短时期下降后恢复到它的正常速率。

在一般情况中,用稍有差别的速度播放一个动画是可以接受的,但是,当要求精确控制或者可见精度是有影响的时候,我们必须考虑帧速率的缺陷。此时,我 们用基于逝去的时间而不是关联于指定帧来计算移动一个移动的距离更合适(即基于速度的动画)

2.  用Timer做动画的原理

Timer类是一个一般的实用程序类,用于在一个特定的时间间隔后执行代码。每个Timer对象在一个程序员指定的频率下调度TimerEvent.TIMER事件。想要在该频率下执行的函数用Timer对象为TimerEvent.TIMER事件来注册。

帧速率对Timer的影响

尽管Timer类看似提供了一个完全随意的方式来在一个指定时期之后执行一个函数,但可能令人惊奇的是,它任然依赖于Flash运行器的帧速率。对 于每次预定屏幕更新检查一个TimerEvent.TIMER事件最多可以产生10次(10倍于帧速率)。例如,给定每秒1帧的一个帧速率,一个 TimerEvent.TIMER事件最多(快)只能每100毫秒执行一次,甚至在一个更小的delay值指定给一个Timer对象的时候。在每秒10帧 的时候,一个TimerEvent.TIMER事件每秒最多可以发生100次(10毫秒每次)。在每秒100帧的时候,一个 TimerEvent.TIMER事件最多每秒可发生1000次(1毫秒每次)。

当一个TimerEvent.TIMER事件设置为运行得比帧速率更不频繁的时候,它将执行于下一次预定屏幕更新的时间间隔之后。为了请求更新于下 次预定更新前,使用TimerEvent类的实例方法updateAfterEvent()。

3.  在Timer和Event.ENTER_FRAME之间选择

帧速率受变化的控制:当一个.swf文件被另一个运用程序装载的时候,该运用程序的帧速率可能和.swf文件指定的帧速率有很大的不同(被装在的帧 速率被屏蔽,统一用运用程序的帧速率),从而导致.swf的动画播放太快或者太慢。被装载的.swf文件当然可以设置帧速率,但是改变帧速率可能导致在父 亲应用程序的不需要的播放行为Timer类提供了一些帧速率的独立性。

使用大量的Timer对象需要更多的内存:在分散动画管理体系结构中,使用一个单独的Timer来控制每个对象动画需要的内存要多于通过类似的 Event.ENTER_FRAME实现可能需要的。

使用大量的Timer对象会导致过度的更新请求:在分散动画管理体系结构中,使用一个单独的Timer和updateAfterEvent()相关 联来控制每个对象的动画导致了对屏幕的多个独立的请求,有可能导致性能的问题。

基于这些因素,这里是一个推荐的最佳操作:

① 在必须使程序内容的显示同步于手工创建于Flash authoring tool(Flash CS3,Flash CS4等)的基于帧内容的显示的应用程序中,使用Event.ENTER_FRAME

② 在Flash运行器中的帧速率的变动必须被减轻的应用程序中,使用单个的Timer对象来编制所有动画,并使用基于速度的动画

③ 当在Flash运行器中的帧速率的变动当做是可以接受的时候,使用Event.ENTER_FRAME(因为使用基于 Event.ENTER_FRAME的动画代码一般要比基于Timer的等价物更简单和使用较少的内存)

④ 避免使用单个的Timer对象来移动单个的显示对象。只要有可能,使用一个单个的Timer对象来编制所有的动画。另外提示一下,如果你想在不 同时间更新不同的对象,单独的Timer对象可能更合适

4.  代码实例

下面我们构建一个运动的矩形,分别使用Event.ENTER_FRAME、TimerEvent.TIMER来实现。整个应用程序构成如下:

F  一个矩形

F  按钮1(Event.ENTER_FRAME)

F  按钮2(TimerEvent.TIMER)

点击按钮1,通过Event.ENTER_FRAME机制使矩形从屏幕的左到右运动起来;点击按钮2,通过TimerEvent.TIMER机制使矩形从屏幕的左到右运动起来。

解析:(1)使用Event.ENTER_FRAME机制,矩形必须监听Event.ENTER_FRAME事件(addEventListener(Event.ENTER_FRAME, animateFrame)),通过相应的事件处理函数animateFrame调整矩形的屏幕位置达到运动的效果。

(2)使用TimerEvent.TIMER机制,timer通过监听TimerEvent.TIMER事件(addEventListener(TimerEvent.TIMER, animateTimer)),通过相应的事件处理函数animateTimer调整矩形在屏幕的位置达到运动的效果。

完整的代码如下:

package 
{
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.TimerEvent;
    import flash.geom.Rectangle;
    import com.bit101.components.PushButton;
    import flash.utils.Timer;
 
    
    /**
     * ...
     * @author Tyler
     */
    [SWF(width=500,height=300)]
    public class Main extends Sprite 
    {
        private var rect:Sprite;
        private var timer:Timer;
        
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            rect = new RectContainer(0, 0, 200, 200);                        
            addChild(rect);        
            
            //设置计时器,每50毫秒出发一次
            timer = new Timer(50);
        
            var enterFrameBtn:PushButton = new PushButton(this, 0, 250, "Event.ENTER_FRAME");
            enterFrameBtn.name = "ENTER_FRAME";
            enterFrameBtn.addEventListener(MouseEvent.CLICK, onClickHander);
            
            var timerBtn:PushButton = new PushButton(this, 120, 250, "Event.Timer");
            timerBtn.name = "TIMER";
            timerBtn.addEventListener(MouseEvent.CLICK, onClickHander);            
            
        }
        
        private function onClickHander(e:MouseEvent):void 
        {
            var name:String = e.target.name as String;
            if (name == "ENTER_FRAME")
            {
                timer.stop();
                rect.addEventListener(Event.ENTER_FRAME, animateFrame);
            }
            else if (name == "TIMER")
            {
                rect.removeEventListener(Event.ENTER_FRAME, animateFrame);                    
                timer.addEventListener(TimerEvent.TIMER, animateTimer);    
                timer.start();
            }
            
        }
        
        private function animateFrame(e:Event):void 
        {
            rect.x += 5;
            if (rect.x >= stage.stageWidth)
            {
                rect.x = 0;
            }
        }
        
        private function animateTimer(e:TimerEvent):void 
        {
            rect.x += 1;
            if (rect.x >= stage.stageWidth)
            {
                rect.x = 0;
            }
            
            e.updateAfterEvent();
        }        
    }
    
}
 
import flash.display.Shape;
import flash.display.SimpleButton;
import flash.display.Sprite;
 
class RectContainer extends Sprite 
{
    public function RectContainer(x:Number,
                                    y:Number,
                                    w:Number,
                                    h:Number) 
    {
        this.graphics.beginFill(0xFFFFFF * Math.random());
        this.graphics.drawRect(x, y, w, h);
        this.graphics.endFill();
    }
 
}
时间: 2024-09-17 03:48:05

走在网页游戏开发的路上(六)的相关文章

大家快来玩转盘抽奖游戏(走在网页游戏开发的路上(七))

.  抽奖流程 其实我们的Flash只是一个显示作用,要转到哪个位置(中哪个奖品)是后台来完成的.而且每个奖品的概率是不同的,不是等概率的,我想没有转盘抽奖游戏是等概率的.从玩家点击"抽奖"开始到结束,与后台的交互如下: 转盘抽奖的大致流程是这样的: F  玩家点击Flash中的"抽奖"按钮: F  Flash调用web页面中的Javascript函数,告诉它玩家开始抽奖了.当然Flash调用JS的时候是带了参数的,比如是谁在抽奖等详细信息: web页面中的Java

走在网页游戏开发的路上(四)

AS3之类 0.  前言 类:面向对象的基础,类是对象的抽象表示形式,类用来存储有关对象可保存的数据类型及对象可表现的行为的信息. 类的定义: [dynamic] [public | internal] [final] class className [ extends superClass ] [ implements interfaceName[, interfaceName... ] ] {     // 此处是类定义 } 在ActionScript 3.0中,可使用以下四个属性之一来修饰

走在网页游戏开发的路上(九)

游戏中的背景音乐和声效 0.  前言 不管是大型客户端游戏还是轻量级的网页游戏,游戏中背景音乐和声效是必不可少的.好的背景音乐.声效会给游戏增色,本文不从策划/设计等角度去考虑,只从程序实现上面讲在网页游戏开发中如何去实现背景音乐.声效.背景音乐和声效有以下几个要求: ü  背景音乐与声效是分开的,可以独立设置开关 ü  背景音乐一般循环播放一直存在 ü  声效点击才触发,这种声音任何时候只播放一个,如果两个瞬间点击多个按钮,只播放最后一个声音 为了使背景音乐和声效分开,可以使用不同的声道来播放

走在网页游戏开发的路上(一)

起步 --此系列谨记录我步入页游开发队伍的历程. 0.写在前面 相信有很多和我一样的人,曾多次问google.问baidu.问各大论坛--如何开发游戏?开发游戏如何入门?由于游戏开发本身其复杂.庞大.涉及东西比较多,始终不得其道,最终激情无情的被时间这把杀猪刀给磨灭.之后又一次激情澎湃,又一次不了了之-- 本人喜欢玩游戏,也有幸在研究生毕业能够加入腾讯QQ游戏开发部门,本系列将记录如何步入网页游戏开发的历程.此系列,至少是目前阶段,主要关注如何使用ActionScript 3.0开发网页游戏(本

走在网页游戏开发的路上(八)

游戏中定时器的设计 0.  前言 在游戏开发中计时器/定时器是必须的,而且会在多处用到,如吃药补血每秒回10点且持续1分钟.玩家从一点到达另一点的过程需要多少时间.下面是定时器在七雄争霸中的几个应用场景,直接上图: 场景1:建筑升级时间 场景2:建筑升级时间 场景3:科技研究时间 类似的场景还有很多,就不一一列举了.但有一点可以肯定的就是,不可能每个地方都去new一个定时器各自管理,这样会消耗大量CPU和内存,从而导致游戏不流畅,画面卡卡的.所有一般游戏中都只维护一个全局的定时器,这也是本文的主

走在网页游戏开发的路上(十一)

游戏中的图像资源 当今游戏早已不再是黑白机的时代,游戏都由色彩丰富.精致的图像,流畅的动画构成.Flash游戏也不例外,Flash既支持矢量图又支持位图,他们各有优缺点.本文的目的即是介绍何时使用矢量图,何时使用位图,如何在两者之间权衡? 1.    前言 首先让我们了解一下何谓矢量图,何谓位图,及各自的优缺点.这些内容与游戏无直接关系,但是了解他们的差异有助于我们在游戏中如何选择. 1.1 矢量图 矢量图(摘自:百度百科)使用直线和曲线来描述图形,这些图形的元素是一些点.线.矩形.多边形.圆和

走在网页游戏开发的路上(三)

AS3之函数 0.  前言 函数:完成某个目标任务的代码块,它是代码重用的最小单位. 函数是可在ActionScript中调用的基本代码单位.ActionScript中用户定义的函数和内置函数都由Function对象来表示,该对象是Function类的实例. 类的方法与Function对象略有不同.与普通函数对象不同,方法和与其关联的类对象紧密关联.因此,方法或属性具有在同一类的所有实例中共享的定义.可以从实例提取方法并将其处理为"绑定"方法(保留与原始实例的链接).对于绑定方法,th

走在网页游戏开发的路上(二)

AS基础过关 0.  ActionScript简介 ActionScript是Macromedia(现已被Adobe收购)为其Flash产品开发的,最初是一种简单的脚本语言,现在最新版本3.0,是一种完全的面向对象的编程语言,功能强大,类库丰富,语法类似JavaScript,多用于Flash互动性.娱乐性.实用性开发,网页制作和RIA应用程序开发. ActionScript是一种基于ECMAScript的脚本语言,可用于编写Adobe Flash动画和应用程序.由于ActionScript和Ja

走在网页游戏开发的路上(五)

AS3事件模型 --AS3的灵魂之一 0.  前言 ActionScript 3.0事件模型使用方便,而且符合标准,它与Adobe Flash Player显示列表(display list)完美集成在一起.ActionScript 3.0的事件模型是基于DOM 3的事件规范[1],是业界标准的事件处理体系结构,为ActionScript 3.0程序员提供了强大而直观的事件处理工具. 为了清晰理解AS3事件模型,我们必须首先知道什么是事件模型?事件模型组成?DOM3事件模型? 1.  事件模型及