使用FLEX和Actionscript开发FLASH 游戏-使用输入和动态背景
在本系列第三部分我们最终得以在屏幕上画一些图形。在第四部分我们将多画图形而且使得游戏对象呈现交互性。我们还将生成一个背景级别使得游戏者可以在其上面飞行。
大多数Flash游戏自然非常简单。它们是5至10分钟的小娱乐,人们在午餐时分可以玩它,或者在老板看不见的时候。这种简单性在Flash游戏的典型控制方案中反映出来:鼠标输入只使用左键单击。这是很直观的(人们抽出他们时间的几分钟来玩游戏可不想阅读一个写着复杂控制方案的帮助页面),总之Flash不会让你(简单地)使用鼠标右键。
谢天谢地我们游戏中的俯视角射手风格非常好地适于这种简单地控制方案。游戏者仅仅在屏幕上到处移动鼠标来移动游戏者飞船,通过单击鼠标左键来发射子弹。但是在我们生成一个代表游戏者飞船的游戏对象之前我们先需要一种能探测鼠标移动到哪了鼠标何时被点击了的方法。让我们看看完成上述功能需要在main.mxml文件中做些什么改变。
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)"
click="click(event)"
mouseDown="mouseDown(event)"
mouseUp="mouseUp(event)"
mouseMove="mouseMove(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();
}
}
private function click(event:MouseEvent):void
{
GameObjectManager.Instance.click(event);
}
private function mouseDown(event:MouseEvent):void
{
GameObjectManager.Instance.mouseDown(event);
}
private function mouseUp(event:MouseEvent):void
{
GameObjectManager.Instance.mouseUp(event);
}
private function mouseMove(event:MouseEvent):void
{
GameObjectManager.Instance.mouseMove(event);
}
protected function startGameClicked(event:Event):void
{
currentState="Game";
}
protected function enterGame(event:Event):void
{
Mouse.hide();
GameObjectManager.Instance.startup();
Level.Instance.startup();
inGame=true;
}
protected function exitGame(event:Event):void
{
Mouse.show();
Level.Instance.shutdown();
GameObjectManager.Instance.shutddown();
inGame=false;
}
]]>
</mx:Script>
</mx:Application>
我们增加了函数来侦听四个新的事件:mouseMove,click,mouseDown和mouseUp。MouseMove,就如同你所希望的,在鼠标移动时被调用。它允许我们通过flash游戏窗口来监听鼠标光标的位置。相似地click在鼠标按钮被点击(即按下并且释放)时监听。当鼠标按钮被按下mouseDown作用,而当鼠标按钮被释放时mouseUp作用。我们特别地需要监听mouseDown和mouseUp事件的能力(click事件与之不同,它在鼠标被点击而且接着释放时调用)因为最终用我们希望鼠标按钮被按下时游戏者开火而当鼠标按钮被释放时停止开火。
四个新函数的事件有着同样的名称作为各自的事件,仅仅将消息传给GameObjectManager。
GameObjectManager.as
package
{
import flash.display.*;
import flash.events.*;
import mx.collections.*;
import mx.core.*;
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;
//a collection of the GameObjects
protected var gameObjects:ArrayCollection=new ArrayCollection();
//a collection of the GameObjects are placed,to avoid adding items
//to gameObjects while in the gameObjects collection while it is in a loop
protected var newGameObjects:ArrayCollection=new ArrayCollection();
//a collection where removed GameObjects are placed,to avoid removing items
//to gameObjects while in the gameObjects collection while it is in a loop
protected var removedGameObjects:ArrayCollection=new ArrayCollection();
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 shoule be instantiated");
backBuffer=new BitmapData (Appliction.application.width,Application.application.height,false);
}
public function startup():void
{
lastFrame=new Date();
}
public function shutdown():void
{
shutdownAll();
}
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;
removeDeletedGameObjects();
insertNewGameObjects();
Level.Instance.enterFrame(seconds);
//now allow objects to update themselves
for each(var gameObject:GameObject in gameObjects)
{
if(gameObject.inuse)
gameObject.enterFrame(seconds);
}
drawObjects();
}
public function click(event:MouseEvent):void
{
for each(var gameObject:GameObject in gameObjects)
{
if(gameObject.inuse)
gameObject.click(event);
}
}
public function mouseDown(event:MouseEvent):void
{
for each(var gameObject:GameObject in gameObjects)
{
if(gameObject.inuse)
gameObject.mouseDown(event);
}
}
public function mouseUp(event:MouseEvent):void
{
for each(var gameObject:GameObject in gameObjects)
{
if(gameObject.inuse)
gameObject.mouseUp(event);
}
}
public function mouseMove(event:MouseEvent):void
{
for each(var gameObject:GameObject in gameObjects)
{
if(gameObject.inuse)
gameObject.mouseMove(event);
}
}
protected function drawObject():void
{
backBuffer.fillRect(backBuffer.rect,clearColor);
//draw the objects
for each(var gameObject:GameObject in gameObjects)
{
if(gameObject.inuse)
gameObject.copyToBackBuffer(backBuffer);
}
}
public function addGameObject(gameObject:GameObject):void
{
newGameObjects.addItem(gameObject);
}
public function removeGameObject(gameObject:GameObject):viod
{
removeGameObjects.addItem(gameObject);
}
protected function shutdownAll():void
{
//don't dispose objects twice
for each(var gameObject:GameObject in gameObjects)
{
var found:Boolean=false;
for each(var removedObject:GameObject in removedGameObjects)
{
if(removedObject==gameObject)
{
found==true;
break;
}
}
if(!found)
gameObject.shutdown();
}
}
protected function insertNewGameObjects():void
{
for each(var gameObject:GameObject in newGameObjects)
{
for(var i:int=0;i<gameObjects.length;++i)
{
if(gameObjects.getItemAt(i).zOrder>gameObject.zOrder||gameObject.getItemAt(i).zOrder==-1)
break;
}
gameObjects.addItemAt(gameObject,i);
}
newGameObjects.removeAll();
}
protected function removeDeletedGameObjects():void
{
//insert the object acording to it's z position
for each(var removedObject:GameObject in removedGameObjects)
{
var i:int=0;
for (i=0;i<gameObjects.length;++i)
{
if(gameObjects.getItemAt(i)==removedObject)
{
gameObjects.removedItemAt(i);
break;
}
}
}
removedGameObjects.removedAll();
}
}
}
正如你所看见的GameObjectManager有了4个新的函数来反映应用程序对象里的4个新的鼠标事件。GameObjectManager依次在gameObjects集合上循环给当前处于活动状态的任何GameObject传递消息。