States & Double Buffer Rendering in Flex 4.0

Written by:  • Edited by: Linda Richter
Updated Dec 9, 2011
• Related Guides: Flash | Bitmapdata | Canvas Element

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.

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

<?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>

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.

Showing page 1 of 2

Comments

Showing all 28 comments
 
Buttrose Dec 9, 2011 3:02 AM
RE: States & Double Buffer Rendering in Flex 4.0
Completely out of date for Flex 4.6 does not work
343245 Nov 11, 2011 12:36 PM
RE: States & Double Buffer Rendering in Flex 4.0
hoho
Allen Jul 14, 2011 6:03 PM
BorderContainer
Am trying to do upgrade your demo to Flex 4 as I work through it. Flex 4 says to use BorderContainer instead of Canvas. When I use Canvas container, the buffer beginBitmapFill works and the blue is displayed. When I use BorderContainer, however, the blue is either not displayed or overwritten. Any ideas about behavior of BorderContainer that causes this? Thanks, Allen
jimmy Feb 4, 2010 9:29 AM
Compiler Error
Hi I am going through your demo. All was good until I got this error from the compiler. THis happened after I completed step 2 and attempted mxmlc mail.mxml. The main and .as files are in bin with mcmlc. _____________________________________________________________ : Error: Access of undefined property GameObjectManager. what gives?? how does main link in the GameObjectManager thanks jimmy
Matthew Casperson Jan 29, 2010 12:28 PM
RE: States & Double Buffer Rendering in Flex 4.0
The GameObjectManager is a singleton. It does have to be instansiated, but this is done through the Instance property. So you do not have to create a new GameObjectManager object - just access the static GameObjectManager.Instance property.

The method I used to create the singleton was flawed (read some of the earlier comments to find out why), but the idea of a singleton is fairly common.
Troy Scheffel Jan 29, 2010 9:13 AM
Singleton vs. static class/methods
I am very new to AS3 programming (being a C/C++/C#/Java programmer). As such I assume that GameObjectManager was not made into a static class because AS3 doesn't support such a thing. Is this correct?

In other words, why does GameObjectManager need to be instantiated vs just using static methods/properties (or static class, if possible)?

Enlightment for a noob AS3 programmer is much appreciated. Take care.
Matthew Casperson Oct 24, 2009 6:19 PM
RE: States & Double Buffer Rendering in Flex 4.0
Your right, as it stands you could create multiple instances of the GameObjectManager. To be perfectly honest I copied and pasted this code from a snippet I found elsewhere and didn't actually look too closely at the implementation :(
Bobby Oct 24, 2009 12:53 PM
Singleton - Last Post
Hmm, you keep pointing me back to the basics. If I'm missing something, I apologize, but I can't help but feel that my affinity for understatement has led you to underestimate and dismiss me. Let me try being bolder. I do not believe the Singleton method used here works the way you think it does. Maybe an example will serve better.

I can do this (as well as use any other functional part of the class)...

var clsGOM_1:GameObjectManager = new GameObjectManager();
clsGOM_1.EnterFrame();

var clsGOM_2:GameObjectManager = new GameObjectManager();
clsGOM_2.EnterFrame();

var clsGOM_3:GameObjectManager = new GameObjectManager();
clsGOM_3.EnterFrame();

...all day long and it will never throw the warning error. Why? Because instance (prop) defaults to null and as long as I don't use Instance (method), it will always remain that way. As long as instance remains null, the if statement in the constructor will never be true despite the fact that I've made 3 (and could have made infinitely more) instances of your object. Unless I'm missing something, the Singleton method used here just doesn't cover the most prime/elemental/fundamental thing that it should be covering.

I doubt either of us has any more time/energy for a topic that isn't critical to this tutorial. The only thing I might argue is that if you're going to include some potentially confusing code in a tutorial that's likely to attract a lot of new developers, it should do what's intended. Otherwise, it's even more confusing.

I've since looked at this code at a site you pointed me to: http://en.wikipedia.org/wiki/Singleton_pattern#Flash_ActionScript

Assuming it works, which is predicated on the necessity that a class constructor executes before any class properties (in this case INSTANCE) are assigned their default value, then it would appear to actually prevent new instances from being created (not just warn about it). That would be the best method I've seen yet.

All the best.
Matthew Casperson Oct 23, 2009 8:16 PM
Singleton
Your approach is essentially what the original code does. Inside the constructor we look to see if the instance (notice the lower case "i") variable is null. If it is, the instance variable is set to the value of the current object and everything is good. However, if the instance variable is not null that means the constructor has been called at least once before and an exception is thrown.

The Instance property (notice the uppercase "I") provides access to the instance (the lowercase one) variable, initialising it if it is null.

The only real difference with this approach as opposed to yours is that the Instance property provides a central location to access the single instance, rather than having to record the value returned by the constructor after the first call in your own code.
Bobby Oct 23, 2009 12:09 PM
Singleton Implementation
Okay, I figured out that my confusion centered on the static keyword. I was under the impression that it was just for scope. I didn't realize the implication on properties (namely, that all instances of an object share the same value for that property).

I'm a little confused though. In my short run at this I've bumped into (but not really studied) several articles about Singleton in ActionScript. It seems to be a hot topic of argument among people smarter than I. Still, I don't think I heard anyone saying there was a way to strictly invoke it...only to inform the developer much in the way the method used here does. To that end, I don't know why this is complicated. The problem I see with the method used here is that it doesn't appear to inform the developer during the most likely misuse of the object. Typically, you use objects by creating instances of them with variables (not calling the class directly). A person could *innocently* create multiple instances with variables and then fully use every functional part of it. As long as they never use the Instance method (and if they're not initiated on Singleton, why would they even think to?), they would be none the wiser because the constructor error would never, ever be thrown.

The answer seems (too?) simple:
-----------------------------------------------
add a global property -
private static iNumInstances:uint=0;

change your constructor -
iNumInstances = iNumInstances + 1;
if (iNumInstances != 1) {
Alert.show("Invalid Singleton use. Please fix.") }

It's a static property, so it should increment on any attempt to create a new object. At this point you could optionally get rid of the instance property and Instance method altogether. That would be a style choice. The main thing is that this bit of code covers the most likely misuse of the object.

What am I missing? It couldn't be that simple, could it? Feel free to criticize. It's all about learning :)
Bobby Oct 23, 2009 5:40 AM
Singleton Implementation
Okay thanks. I guess the source of my confusion was how to trip a constructor for an instance of an object more than once. After spending a couple hours not being able to do it, now I find myself doing it all the time and for reasons I don't quite understand. Ah, but I guess those are questions for another forum :)

Cheers
...and thanks for the tutorial and so actively supporting it.
Matthew Casperson Oct 22, 2009 5:29 PM
Singletons
Singletons in ActionScript are complicated because you can not have a protected or private constructor. In a language like C++ a singleton would be defined (and enforced by the compiler) thanks to the fact that an outside class could not call the protected constructor (in conjunction with the new keyword).

In Actionscript you have to settle for throwing an exception when more than one instance of an object is created. It won't actually stop more than one instance being created, but hopefully it will make a developer stop and think about the reason why more than one instance is needed (rather than catch the exception and ignore it).

See http://en.wikipedia.org/wiki/Singleton_pattern#Flash_ActionScript and http://www.darronschall.com/weblog/2007/11/actionscript-3-singleton-redux.cfm for more info.
Bobby Oct 22, 2009 11:14 AM
Singleton Implementation
Hi Matt, I'm 72 hrs (minus sleep/eat/poop) into this whole Flash/Flex/MXML/ActionScript thing. In fact, I got started by finding your tutorial and dowloading the tools you suggested. I spent a few hours doing your first 2 chapters and then switched to pouring through Adobe docs to get a better feel for the structure/language. Consequently, I know just enough to be dangerously ignorant :)

Anyway, I'm back to your tutorial and want to ask you about your Singleton implementation before I proceed to Chapter 3. Namely, I don't get its reasons/consequences. As near as I can tell, there's nothing that prevents another developer from creating countless instances of the GameObjectManager class with object variables and then using all the properties and methods other than instance (property) and Instance (method). On the plus side, if one were to use object variables in concert with Instance, they would get a compile error. If that's all it was, I suppose I could see an argument for it. What I'm baffled by is the inclusion of the "throw new Error" statement. I get how that would end execution of that function, but what I don't get is when that would ever be triggered. To my (pea-brained) way of thinking, you could create many instances of an object with object variables, but if you're referencing the class definition directly by name (possible source of confusion), could there ever be more than one? And even if there could, I'm thinking each instance property would be tied to itself. I mean I can create countless instances of the object with variables and that error is never triggered because it's not actually looping through and testing all the objects that are part of the application.

So, I just don't get it. Any explanation would be appreciated, but if you could just provide an example of how to trip that code, that would probably illuminate for me its purpose and perhaps give me some insight into Flex/ActionScript object creation.

Much obliged :)
Aki Oct 5, 2009 1:23 PM
Double buffering
Hello, it's me again.
I ran some tests with double buffering vs. not.

http://pastebin.im/118
http://pastebin.im/119

Couldn't get a clear winner. I thought it might be a difference with the filling, but when I tried with only 2 objects:

http://pastebin.im/120
http://pastebin.im/121

I couldn't get a clear winner either. Without double buffering it seems to be very slightly faster, but they're so close it could be just a statistical error. Here are the results I got:

http://pastebin.im/122
Aki Oct 5, 2009 8:42 AM
game loop
Erf, of course I messed up and put the "currentTime = new Date().getTime()-dt;" in the wrong place. Of course that's not the place for initialization variables...

Also forgot the pluses from the "loop", like sigs mentioned.
sigs Oct 4, 2009 4:28 PM
a maths/physics note...
"With the example of the asteroids clone, your claim that the acceleration is based on your FPS in not correct. Technically your acceleration would be a fixed value, and the amount that your ships moves would be determined by a formula like s = ut + 0.5 at^2"

actually, that's not true. Try it out with pen and paper. If you do

v += a * dt;
s += v * dt;

you get different s for different dt.
Aki Oct 3, 2009 2:55 PM
game loop
ziggy-article:
Yes, you CAN do continous collision detection (as I mentioned) but you might not HAVE TO if you use constant dt.

asteroids:
As with the ball example, I assumed the simplest way of:
loop {
v = a*dt;
x = v*dt;
}
I was supposed to mention better integration in my last comment's second to last chapter, but ran out of characters. But the whole point is that again you don't have to worry about those things. It doesn't matter if it's not exactly correct physics in an asteroids game, just as long as it doesn't change with FPS.

Here's how to do it:
Remove the three lines from GameObjectManager.as that deal with time, change definition to "public function enterFrame(dt:Number):void" and use "dt/1000.0" instead of seconds in the two function calls.

Add these to main.mxml after the CDATA thing:
****
protected var currentTime:Number;
protected var dt:Number = 20;
protected var accumulator:Number = 0;
****

Change the main.mxml's enterFrame to:
****
public function enterFrame(event:Event):void
{
currentTime = new Date().getTime()-dt; // new
if (inGame)
{
var newTime:Number = new Date().getTime(); // new
var deltaTime:Number = newTime - currentTime; // new
currentTime = newTime; // new
accumulator += deltaTime; // new
while(accumulator >= dt && inGame) // new
{
GameObjectManager.Instance.enterFrame(dt);
accumulator -= dt; // new
}

myCanvas.graphics.clear();
myCanvas.graphics.beginBitmapFill(GameObjectManager.Instance.backBuffer, null, false, false);
myCanvas.graphics.drawRect(0, 0, this.width, this.height);
myCanvas.graphics.endFill();
}
}
****
(of course you might want to clean it up a bit, by using a global constant etc)
That's 10 new lines with code and 3 lines removed, not too bad for something that will save lots of trouble later and is a lot less error prone.
Matthew Casperson Oct 2, 2009 7:06 PM
RE: States & Double Buffer Rendering in Flex 4.0
I see your point, and fixing the framerate would involve adding maybe 1 additional loop to the EngineManager class. But you would still want to calculate your movement and triggers based off the time that has passed during a frame - be that a fixed constant value or a variable amount of time. So the code would go from
position = speed * direction * dt
to
position = speed * direction * FIXED_FRAME_RATE
Otherwise if you wanted to change the framerate you'd have refactor every time based calculation.
The real issue here is not using a render loop or time based calculations that involve a "dt" value - almost every Newtonian or physics formula is based on change over time. It's that the dt value itself might not be constant.
With the example of the asteroids clone, your claim that the acceleration is based on your FPS in not correct. Technically your acceleration would be a fixed value, and the amount that your ships moves would be determined by a formula like s = ut + 0.5 at^2. Although fixing the timestep would reduce or eliminate the chance the player would pass through another object (though you can see a solution for this type of problem at http://www.ziggyware.com/readarticle.php?article_id=178).
There are some considerations to make when fixing the timestep. What do you do about sound effects? If a PC is playing the game so slowly that you have to add an additional 5 shots of a weapon in one frame, do add the 5 weapons and then play the sound effect 5 more times? Also, for the sake of consistency, you would have to interpolate the mouse movement over the "internal frames" that would be calculated for every frame that is actually drawn to the screen. And of course you would have to differentiate between those "internal frames", so you don't bother drawing anything for that frame, as opposed to the final "internal frame" that will be flipped to the screen.
I agree that fixing the timestep is a useful idea, but other aspects had to be covered in the 10 articles
Aki Oct 2, 2009 6:40 AM
game loop
It's not only physics engines. And fps only puts a CAP on it, it doesn't give any minimum rate.

Think about a game where you move a character and have to avoid bouncing balls. If you do it the easy way: "ball.velocity -= dt*gravity", the bounce altitude might change and the game will be harder or easier depending on the computer.

Or maybe you have a tile based rpg or similar where you walk around. If you're walking towards a wall, and the computer has a hiccup. the dt might suddenly jump and the character will go through the wall.

Or if you're playing a space shooter. It's the last level and there's a huge wave of enemies coming, causing old computers to drop the fps to something like 5. Especially if you're using a mouse, you can just jump through the wave without getting hit. Only problem is that all your über-cool weapons that should be shooting 10 times per second are only shooting 5 times per second.

Or how about an asteroids-clone. Again, your acceleration would depend on the fps. Your firing rate might depend on the fps. The bullets might go through the smaller rocks, depending on the fps. YOU might go through the smaller rocks, depending on the fps.

Or tetris-clone? It would be impossible without some kind of event queue system, otherwise you'd run into troubles if the blocks move faster than than fps. The even queue would be functionally equivalent to my suggestion though. (Or timers, but there are problems with those too.)

I could carry on and on. Especially with hiccups. Of course you CAN go around most of those problems by coding stuff like continuous collision detection, error messages for slower computers, slowing down the game (another thing I could write an essay on), but any of the solutions are a lot more work than fixing the timestep in the first place.

The dt-loop is a lot harder to code for and just as easy to start with. I might be new to Flex, but I have made games and I've never seen a situation where it would be better.
Matthew Casperson Oct 1, 2009 6:51 AM
dt in fameloop
The dt value is a little redundant in Flash because the framerate is somewhat fixed anyway - the framerate attribute you assign to the main Flex Application object will put a cap on the framerate.

Physics engines are a bit of a special case though - the whole physics system can literally explode (or at least the constraints will fail) over a long frame time. I don't know that it makes any real difference one way or the other for a 2D game where all the objects move in straight lines.
Aki Oct 1, 2009 4:40 AM
game loop
Excellent tutorials.
There's just one minor (actually, major :P) gripe: the dt based game loop.

For some reason that's what usually pops up in beginner tutorials for game programming. I guess it might be that the looping is easy to implement and understand. Personally I think it should never used even in tutorials, because people might end up using it in their final game. Problem is that it starts to get hard to program with a bit more complexity and the game handles very differently depending on the fps. (And thus, computer.)

I could carry on, but luckily Glenn Fiedler has explained it very well:
http://gafferongames.com/game-physics/fix-your-timestep/
Of course that's for C++ and game physics with fancy integration, but it applies to this sort of loop-based game programming in every language, except you don't have to do the last "final touch". Just replace the "integrate(state, t, dt);" in "Free the physics" by "enterFrame()" or similar, without dt, as it would be constant anyway.
Matthew Casperson Aug 25, 2009 7:45 AM
Do you really need double buffering?
That's a good question. Even without the visual tearing double buffering seems to have some performance benefits.

http://www.bit-101.com/blog/?p=1040

http://jessewarden.com/2005/11/blitting-double-buffering-for-tile-based-games-in-flash-flex-part-1-of-3.html

That said though I have not actually compared the speed benefits of single vs double buffering for myself, but it would be fairly easy to modify the render loop so as to only use one buffer.
Julian Aug 25, 2009 5:37 AM
Do you really need double buffering?
I'm wondering if you need the double buffer at all.

Have you tried having just one Bitmap on screen?

I'm pretty sure FlashPlayer updates the content of the Stage once per frame by default.

This means you can safely modify the visible bitmap many times between one update and the next one.

You won't get any "visual tearing" as you can't really draw directly to the screen in FlashPlayer.

Just wondering.

Cheers,
Julian
Matthew Casperson Aug 22, 2009 10:35 PM
Compiling
I actually compiled the game via Flex Builder. You can still compile the game with the free command line tools, but the Flex Builder will save you a lot of trouble. You can grab a trail version from the adobe website.
Doron Aug 22, 2009 7:41 PM
Got the compiling it to work
@Dan: Googled it a little and you have to do the following:
Name the file GameObjectManager.as - it should be spelled exactly like the class name, and the file must reside in the same directory as the main.mxml file.
In addition, right before the
protected var inGame:Boolean = false;
declaration, you should enter the following line:
import GameObjectManager;

That's what worked for me.

@Matthew - Really great article. Following the rest now :)
Albert Aug 14, 2009 12:13 PM
Including the .as file into main.mxml
Hey Dan, here you go.

<mx:Script source="GameObjectManager.as"/>
yongxi xue Aug 13, 2009 10:14 PM
an excellent article
It's reallly an excellent articel.I am studying and exercise it step and step,thought there is a little difficulty for me.I started to study flex a few months ago,and this articel must be useful for the new user.
Thanks!
Dan Jul 31, 2009 10:49 PM
How do you build this?
Running mxmlc on main.mxml file has an error, asking what GameObjectManger is. main.mxml file doesn't include GameObjectManager.as, so I'm assuming you have to build it in such a way that they see each other. In the previous section, you showed the command to build it. Here you did not, so I'm still trying to figure it out. Could you edit it in?

Thanks!

Dan
 
blog comments powered by Disqus
Email to a friend