Flash 4.0 Game Development with Flex and Actionscript: Double Buffer Rendering
In part one of the series we created the initial Flex application class. In part two we will be adding states and a double buffered rendering process.
States are quite self explanatory: they represent the different states that a program can be in. For example a shopping cart might have one state for browsing the store and another state while looking at the details of a particular item. Our game will also have a number of states which will include the main menu, the game play itself, the end of level summary and maybe a high score screen.
Flex includes native support for states. These states were designed with a transition from one GUI to another in mind, but they have the functionality we need to change between states that don’t necessarily have any GUI components. Modifying the currentState property of the Application will trigger a state change, and by adding the required startup and shutdown code to the functions associated with the enterState and exitState events we can update the internal game state to match.
Double Buffering is a technique used to remove the visual tearing associated with drawing directly to the screen. It gets its name because you use two graphics buffers to draw the final image: one that resides in-memory (the back buffer), and the buffer which is displayed on the screen (front buffer). You can think of the back buffer as a kind of scratch pad which is built up as the individual elements that make up the final scene write to it. Once a frame has been drawn it is copied to the front buffer in one operation. The screen then displays the contents of the front buffer.
So let’s look at how these concepts are implemented in Flex.
Explaining the Concepts
<mx:Application
xmlns:mx="https://www.adobe.com/2006/mxml"
layout=“absolute”
width=“600”
height=“400”
frameRate=“100”
creationComplete=“creationComplete()”
enterFrame=“enterFrame(event)”
currentState=“MainMenu”>
<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”/>
<![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>
The first thing to notice is the addition of the currentState property to the mx:Application element. As mentioned above, the currentState property of the Application object defines the current state of the program. By setting it to MainMenu through this attribute we are saying that the program should start in the MainMenu state.
We have also added a mx:States element. This element defines the states that the program can take through the child mx:State elements. We have defined two states to start with: MainMenu and Game. In the MainMenu state the end user will see the starting screen of the game. The Game state represents the gameplay itself.
Both mx:State elements have a name property. This property is the name of the state, and by changing the currentState property of the Application object to this name we can transition into the state. The Game state also includes two more properties: enterState and exitState. By associating functions with these events we have an opportunity to manually “sync” the internal game logic to this state. As you can see we use the EnterGame function to startup the GameObjectManager (more on that class later) and set the internal flag inGame to true. The inGame flag is used during the rendering loop to allow the game to draw to the screen. The ExitGame function simply sets the inGame flag to false, which allows a GUI to be displayed.
Remember how I mentioned that the states in Flex were designed with GUI transitions in mind? The MainMenu state shows how easy this is. The mx:AddChild element is used to add a GUI element to the state. In this case we use it to add a button that the player can click to get into the game. But as soon as we leave the MainMenu state Flex will automatically remove the button without any additional code or effort.
To allow us to render to the screen we have added a mx:Canvas element. The canvas (or more specifically its graphics property) will serve as the front buffer in the double buffering rendering process. The back buffer exists in the GameObjectManager class. During the enterFrame function we call the GameObjectManager’s enterFrame function, which will allow it to draw the back buffer. Once the frame has been drawn we take the back buffer and draw it onto the canvas using the clear, beginBitmapFill, drawRect and endFill functions of the canvas’s graphics property.
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);
}
}
}
The GameObjectManager object will be responsible for managing the elements that will make up the final game like the enemies, the player and the various background elements. It is also responsible for managing the back buffer to which these elements will draw themselves to. If you recall the front buffer was implemented as a canvas element. This was for convenience as a canvas can be added directly as a child of the Application object. The back buffer is implemented as a BitmapData object, which allows us to quickly and directly manipulate the pixels that make up the final image.
The clearColor property specifies the colour that will be used to wipe the back buffer before the scene is built up. Eventually the entire back buffer will be overwritten by the game elements, which makes this color irrelevant, but for now it is quite important because it will make up a good chunk of the final frame. The value 0xFF0043AB is a dark blue. The first two hex values (those after the 0x) represent the alpha: FF for opaque and 00 for transparent. The next 6 hex values make up the red (00), green (43) and blue (AB) components.
The static instance property is used with the Instance function to implement the Singleton design pattern. Basically we only ever want one GameObjectManager to exist in the program (hence the name), and by referencing the GameObjectManager through this instance property we can be assured that only one GameObjectManager will ever be created. The Singleton design is quite a common programming paradigm, and while ActionScript lacks support for a protected constructor it still useful as a self documentation tool (if you ever see an Instance property, chances are that the object is designed as a Singelton).
The lastFrame property simply stores the time when the last frame was rendered. By keeping a track of this time we can determine how long it has taken between the last frame and this current one, which (will eventually) in turn allows us to update the game elements by this amount. Even though we don’t have any game elements yet the time between frames is calculated in seconds during the enterFrame function. The lastFrame time is reset during a call to startup. This is because the GameObjectmanager is not updated while the program is not in the Game state. If we didn’t reset lastFrame the first frame of the next level would be equal to the time the player spent in the menus in between levels. The player could end up jumping halfway across the level during the first frame, which is definitely best avoided.
So, what have we achieved here? By implementing states we have created a menu screen, from which the player can enter the game by clicking a button. The “game” itself is just an implantation of a double buffer, which draws a blue background. However with the states and rendering implemented we can finally get to the fun stuff: drawing to the screen.
Go back to Flash Game Development with Flex and ActionScript
Related Files
Related Article
**
Create your own Flash adventure game
This tutorial series shows you how to create a simple Flash RPG / adventure game.
This post is part of the series: Game programming with Flex
Learn how to create a Flash game using Flex with this step by step series.
- Flash Game Development with Flex and Actionscript - Getting Started
- States & Double Buffer Rendering in Flex 4.0
- Flex & Actionscript Tutorial: Adding Game Actions
- Creating an Interactive Animated Background With Flex and Actionscript
- Adding Weapons to Your Game: Flex & Actionscript Tutorial
- Collision Detection With Actionscript
- Adding Bitmap Animations With Flex and Actionscript
- Adding Music and Sound FX With Flex and Actionscript
- Defining Levels: Game Design With Flex and Actionscript
- Actionscript Tutorial: Add a Scrolling Tiled Background