使用Flex和Actionscript开发Flash游戏 —— 双缓冲渲染
在该系列的第一篇文章中,我们创建了Flex程序类。这一部分,我们将加上一些states和一个双缓冲渲染流程。 States就如同它自己的名字那样去解释:它表示一个程序所包含的所有状态。
在该系列的第一篇文章中,我们创建了Flex程序类。这一部分,我们将加上一些states和一个双缓冲渲染流程。 States就如同它自己的名字那样去解释:它表示一个程序所包含的所有状态。例如:一个在线商店会拥有一个状态让顾客浏览商店,还有一个状态查看某一特定商品的详细内容。我们的游戏也拥有一些状态,包含:主菜单、游戏自身、关底信息以及一个排行榜。 Flex自身支持多状态(states)。这些状态之间可以相互变化,并伴随着变化动画。但是状态的变化也离不开程序员设置不同状态间功能的变更,这种变化并不必须依赖于用户界面的变化。修改Application的currentState属性将导致状态的转变,同时为enterState和exitState两个事件编写相应的方法,我们就可以更新游戏内部相应的各状态了。 双缓冲是一种用于避免程序直接绘制到屏幕产生画面不连贯的技术。正如它的名字一样,它采用两个绘制缓冲空间来绘制最终图像:一个久驻内存的后置缓冲和一个用于屏幕显示的前置缓冲。你可以这样理解,后置缓冲是一个草稿画板,你可以在上面绘制独立的元素来组成最终的场景。一旦一帧画面在后置缓冲区中绘制完成,它就将图像拷贝的前置缓冲区中,然后屏幕显示前置缓冲区中的内容。 接下来我们看看这个概念在Flex中如何实现。 main.mxml <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="600" height="400" frameRate="100" creationComplete="creationComplete()" enterFrame="enterFrame(event)" currentState="MainMenu"> <mx:states> <mx:State name="Game" enterState="enterGame(event)" exitState="exitGame(event)"> </mx:State> <mx:State name="MainMenu"> <mx:AddChild relativeTo="{myCanvas}" position="lastChild"> <mx:Button x="525" y="368" label="Start" id="btnStart" click="startGameClicked(event)"/> </mx:AddChild> </mx:State> </mx:states> <mx:Canvas x="0" y="0" width="100%" height="100%" id="myCanvas"/> <mx:Script> <![CDATA[ protected var inGame:Boolean = false; public function creationComplete():void { } public function enterFrame(event:Event):void { if (inGame) { GameObjectManager.Instance.enterFrame(); myCanvas.graphics.clear(); myCanvas.graphics.beginBitmapFill(GameObjectManager.Instance.backBuffer, null, false, false); myCanvas.graphics.drawRect(0, 0, this.width, this.height); myCanvas.graphics.endFill(); } } protected function startGameClicked(event:Event):void { currentState = "Game" } protected function enterGame(event:Event):void { GameObjectManager.Instance.startup(); inGame = true; } protected function exitGame(event:Event):void { inGame = false; } ]]> </mx:Script> </mx:Application> 复制代码首先要注意currentState属性的加入。正如前面说过的,currentState属性定义了当前程序的状态(state)。我们将currentState设置为MainMenu,表示程序是由MainMenu状态开始的。 我们同样加入了mx:States元素。这个元素定义了程序所包含的所有子状态。这里我们定义了MainMenu和Game两种状态。在MainMenu状态中,最终用户将看到开始界面。而Game状态表示游戏本身。 这两个mx:State都拥有name属性。改变currentState属性的值,我们就可以完成状态之间的切换。Game状态包含了enterState和exitState两个事件。我们可以使用为这两个事件添加响应函数的方法来手工“同步”游戏内部逻辑。你看到,我们使用EnterGame函数来启动GameObjectManager(之后将提到)实例,并且设置内部标志inGame为true。这个标志在游戏渲染循环中使用,表示是否需要将游戏画面渲染到屏幕。ExitGame方法简单的将inGame标志设置为false,使用户界面不可见。 记得我提到过Flex中的各种状态可以进行切换?MainMenu状态展示了其简单的实现方法。mx:AddChild节点用于添加图形界面元素。在这里,我们添加一个按钮,使用户可以点击进入游戏。当我们离开MainMenu状态时,Flex会自动移除按钮而不需要任何其它代码和设置。 为了将画面渲染到屏幕,我们添加一个mx:Canvas元素。canvas(更具体的说是它的graphics属性)充当了双缓冲渲染流程中前置缓冲的角色。后置缓冲存在于GameObjectManager类中。在enterFrame函数中,我们调用GameObjectManager中的enterFrame方法,该方法允许将画面绘制到后置缓冲区中。每当一帧绘制完毕,我们使用canvas中graphics对象的clear, beginBitmapFill, drawRect和endFill方法将其绘制到canvas上。 GameObjectManager.as package { import mx.core.*; import mx.collections.*; import flash.display.*; public class GameObjectManager { // double buffer public var backBuffer:BitmapData; // colour to use to clear backbuffer with public var clearColor:uint = 0xFF0043AB; /// static instance protected static var instance:GameObjectManager = null; // the last frame time protected var lastFrame:Date; static public function get Instance():GameObjectManager { if ( instance == null ) instance = new GameObjectManager(); return instance; } public function GameObjectManager() { if ( instance != null ) throw new Error( "Only one Singleton instance should be instantiated" ); backBuffer = new BitmapData(Application.application.width, Application.application.height, false); } public function startup():void { lastFrame = new Date(); } public function shutdown():void { } public function enterFrame():void { // Calculate the time since the last frame var thisFrame:Date = new Date(); var seconds:Number = (thisFrame.getTime() - lastFrame.getTime())/1000.0; lastFrame = thisFrame; drawObjects(); } protected function drawObjects():void { backBuffer.fillRect(backBuffer.rect, clearColor); } } } 复制代码GameObjectManager对象承担着管理各种游戏元素的责任,包括敌人,玩家和各种背景元素。它也决定着后置缓冲区中哪些元素需要进行绘制。如果你记得前置缓冲器是由canvas元素实现的,最简单的方式就是将canvas作为一个Application的子节点直接加入。后置缓冲区由BitmapData对象实现,这样我们可以快速直接的操作像素来绘制最终图像。 clearColor属性设置的颜色表示用于在场景建立好之前,清除后置缓冲区的颜色。最终整个后置缓冲区将会被游戏元素覆写,使得clearColor完全不相关,但是目前它非常重要,因为它将建立一块最终帧。0xFF0043AB代表深蓝色。前两位代表alpha值,后6位代表红绿蓝值。 静态的instance属性用于实现单件模式。我们的程序中只需要一个GameObjectManager实例,引用这个静态的属性将保证我们只会创建一个GameObjectManager实例。单件模式是程序设计范例中非常常见,尽管Actionscript不支持protected构造函数,但是单件模式依然十分有用(一旦你看到instance属性,这个类很可能就是按照单件模式设计的)。 lastFrame属性存储了最后帧渲染完毕的时间。跟踪这个时间,我们就可以知道最后一帧于当前帧之间的时间间隔,使得我们可以以此更新游戏元素。尽管目前我们没有任何游戏元素,在enterFrame方法中,我们计算了帧于帧之间的时间。lastFrame时间就是在调用startup时被重置。这是由于当整个游戏不在Game state状态下时,GameObjectManager并不更新。如果我们不重置lastFrame,下一关的第一帧将等于玩家在关间菜单所花的时间。最好要避免玩家在第一帧时终止退出。 所以,我们做了些什么呢?为了实现各种状态,我们创建了主菜单画面,可以使用按钮进入游戏。游戏中我们实现了双缓冲模型,可以绘制一个蓝色背景。接下来,我们就会开始做有趣的事情了,在屏幕上绘制一些东西。 最终结果: http://flexfighters.sourceforge.net/flexfighters2.html 源代码: https://sourceforge.net/project/ ... p;release_id=631382 转自:http://flash.9ria.com/thread-35268-1-1.html |