Flash Game Development with Flex and Actionscript(No.3)

In part 3 we will add some graphics resources and display them on the screen.

When writing a new program there is always a point where you first get to see the fruits of your labour. With the state and rendering “plumbing” now done we can start doing some fun stuff by adding graphics to our game and displaying them on the screen. But before we do let’s take a look at what changes we have to make in the main.mxml file.

在第三部分,我们将添加图样资源并显示在屏幕上。当你写一个程序的时候你总是会感觉到这个阶段是你第一个能看到有所收获的时候。接着我们已完的部分我们开始做有趣的东西啦,添加图片并直接把它们显示到屏幕上。但做之前我们首先看一下我们在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)"

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

{

GameObjectManager.Instance.shutdown();

inGame = false;

}

]]>

</mx:Script>

</mx:Application>

There is only one change made to the exitState function which calls the GameObjectManager shutdown function. This will allow the GameObjectManager to clean up its resources when we leave the Game state. Now let’s move onto the changes to the GameObjectManager.

 

我们只做了一点改动,在exitGame函数里添加了shutdown函数。这将允许我们改变状态时GameObjectManager 可以清空资源。好,现在让我们进入GameObjectManager页面看有哪些改动。

GameObjectManager.as

package

{

import flash.display.*;

 

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 where new 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 should be instantiated" );

 

backBuffer = new BitmapData(Application.application.width, Application.application.height, false);

}

 

public function startup():void

{

lastFrame = new Date();

 

new Bounce().startupBounce();

}

 

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();

 

// now allow objects to update themselves

for each (var gameObject:GameObject in gameObjects)

{

if (gameObject.inuse)

gameObject.enterFrame(seconds);

}

 

drawObjects();

}

 

protected function drawObjects():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):void

{

removedGameObjects.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 ||

gameObjects.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.removeItemAt(i);

break;

}

}

 

}

 

removedGameObjects.removeAll();

}

}

}

 

 

Here we have added 3 new variables: gameObjects, newGameObjects and removedGameObjects. The gameObjects collection will hold all the GameObjects that exist in the game (the GameObject class is used to represent any element in the game, and is described below). GameObjectManager will loop through this collection to update and render the GameObjects. The other two collections, newGameObjects and removedGameObjects, hold GameObjects that have been created or removed during the render loop. The reason for this is because it is almost always a bad idea to modify a collection while you are looping through it. The following code is an example of what you want to avoid.

for each (var gameObject:GameObject in gameObjects)

{

// this is a bad idea…

gameObjects.addItemAt(1, new GameObject());

gameObjects.removeItemAt(2, new GameObject());

}

This is not just a limitation(限制) of ActionScript or Flex; a number of programming languages expressly prevent the modification of a collection while looping over it. Even if it is possible to modify a collection inside a loop it is still a bad idea because the code becomes very hard to debug if something goes wrong. We avoid this situation by adding all newly created GameObjects into the newGameObjects collection (via the addGameObject function) and adding any GameObjects that have been shutdown into the removedGameObjects collection (via the removeGameObject function). These two collections then get “synced” with the main gameObjects collection before we enter a loop through the insertNewGameObjects and removeDeletedGameObjects functions.

To the startup function we add code to create and initialise a Bounce object. This object will not be part of the final game, but exists as a demonstration of how to extend the GameObject class to create an element within the game. The code for the Bounce class will be detailed below.

Our shutdown function, which used to be empty, now calls shutdownAll. ShutdownAll in turn calls shutdown on all GameObjects that have been created. This way we can clean up all GameObjects with one call to the GameObjectManagers shutdown function when leaving the Game state (via the exitGame function in our Application class).

Enterframe has been updated to include calls to the insertNewGameObjects and removeDeletedGameObjects, which as mentioned before allow the gameObjects collection to reflect any GameObjects that have been started or shutdown. We also loop over the gameObjects collection and call enterFrame on all the GameObjects. The enterFrame function in the GameObject class is where the GameObject (and any class that extends it) will update itself. For example an enemy will update its position on the screen during a call to enterFrame. Finally we make a call to drawObjects, which prepares the back buffer and then calls copyToBackBuffer on all GameObjects. It’s in the copyToBackBuffer function that a GameObject will draw itself to the frame.

Now that we have seen how the GameObjectManager manages a collection of GameObjects, let’s look at the GameObject class.

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值