by Samuel Asher Rivello
The entertainment industry continues to shift toward interactive gaming content, and the competition to captivate users has never been fiercer. In 2009, revenue generated from the gaming industry beat out the film industry for the first time. What's more, game revenue is expected to grow 12% globally this year to reach $36 billion. Online gaming is a significant part of the industry, and you can be sure that entertainment bigwigs as well as indie developers are clamoring to create and license winning games on the web.
While there is no single solution for creating a great online gaming experience, you can greatly improve the enjoyment-to-production-budget ratio by considering a few things.
First, adding social aspects to games will build community. Many gameplay mechanics for a single-player experience will benefit from multiplayer functionality. If you spend development resources to create an environment and tools where social interaction can take place, then much of the fun comes organically from social interaction.
Second, as a game designer, you can greatly engage users with a departure from hackneyed gameplay mechanics. Users are attracted to unique experience they can't find elsewhere. Physics-based gaming can give your game development repertoire a huge boost, enabling sandbox-style game mechanics and emergent gameplay.
We live in a real world ruled by real physics. So we expect everything to act as if it was in the world we are used to living in. Consider the PC game Max Payne with its rag doll character physics. The game would not be nearly as much fun without such realism.
— Emanuele Feronato, Box2DFlash game developer, EmanueleFeronato.com
Physics games created with Flash software have been popular for a decade. Some of the biggest blockbuster games are physics-based such as Line Rider. But recently, there has been an explosion of great physics games for Flash, including the addictive, innovative gameplay of Wake the Royalty.
In this article, I discuss the types of physics games you can create with Adobe Flash technology and examine the ROI of adding physics to your existing games as well as creating all new physics-based game experiences. I review the basics and go in depth with two examples. Readers may experiment and republish the projects via Adobe Flash CS4 Professional or simply read along. All the source code is shown in this article and is available for download.
Practically any project that involves some sort of interaction between physical objects can benefit from physics. Creating your physical world inside the physics world allows you to model movements and interactions more uniformly and realistically and to intuitively add additional effects at any time like object destruction and explosions.
— Matthew Bush, creator, Box2DFlash
Flash is a number-crunching powerhouse and can support the rapid mathematics needed for physics calculations. While physics is not native to the Flash Player API, third-party libraries provide the needed algorithms. The integration of physics can improve your existing non-physics-based games with new enhancements. Imagine innovating on a classic game like Asteroid to enable the asteroids to bounce convincingly off of each other instead of passing through each other like in the original game. Physics can do just that.
Beyond improving existing games, game physics unlocks all-new forms of gameplay that are impossible without rigid body dynamics.

Figure 1. Fantastic Contraption, a Flash puzzle physics game.
An exemplary Flash puzzle physics game is Fantastic Contraption. This game would not even be possible without a strong physics engine. The objective in each level is to move all red objects from a blue starting area, past obstacles, and into a red goal area (see Figure 1). The user adds components (such as gears, pulleys, and so forth) to the environment, creating a simple machine to solve the level. You may think that with just five components, the gameplay would be limited. However, the complexity of the object interactions in the world allows for sandbox-style gameplay where you feel the freedom of a child with a pile of toys. This freedom fuels and rewards the player's creativity and makes for a very engaging game experience.
The programming required to perform accurate, efficient physics simulations is daunting. For most intermediate and even advanced Flash developers, the mathematics required is out of reach. Thankfully, the community has responded with various physics libraries (also referred to as physics engines) that do the heavy lifting for you. Not all of these libraries are created equal, however.
Over the past ten years, Flash developers have created engines to solve physics interactions. Many of those projects have lost their support and died off, but a few are powerful and still active. Here are some of the more recent offerings that are free to use and compatible with ActionScript 3:
Some libraries, such as APE, Fisix, FOAM, Wow-Engine(3D), and Motor Physics 2, showcase impressive features but are not ideal for production use because they are either in early alpha stage or they are outdated.
A few of these options are acceptable for production use. In this article, I use Box2DFlash because it incorporates all the benefits of its powerful predecessor (Box2D), it runs smoothly and dependably, it has a robust community, and it is regularly updated and improved. Box2DFlash even powers the Fantastic Contraption game, shown in Figure 1.
The original Box2D project is a fantastic software-based physics simulation library created by Erin Catto. Debuted at the Game Development Conference in 2006, Box2D is written in platform-independent C++. It has been ported to other languages such as C#, Java, JavaScript, Python, and ActionScript.
The Box2DFlash library is the port to ActionScript 3 by Flash developer Matthew Bush. It works great and apparently is updated whenever the original Box2D library is updated. With a strong community and ongoing support, Box2DFlash is a big win for Flash Platform game developers. It has been used to power hundreds of online games you can play today.
Box2DFlash does many things well. Using Box2DFlash, you can:
Using Box2DFlash is not without its drawbacks though. Todd Kerpelman, creative director at NeoEdge, authors Kerp.net — a fantastic Box2DFlash tutorial site. He loves the library but points out some of its weaknesses. According to Kerpelman, “Box2DFlash is not particularly ActionScript centric. For instance, rather than using the built-in Flash flash.geom.Point class, it has its own class that works similarly to Point, but just different enough that it'll probably mess you up the first few times you try using it. Also it's slower than some other engines when dealing with certain [calculations].”
Box2DFlash shares the same C++ style API as the original Box2D (for example, b2Body.GetMass(); and b2Body.m_invI;). This is a benefit because developers can find code snippets to common algorithms from any Box2D port, and it's likely that the snippets will work in the ActionScript 3 version. However this API style looks a little foreign to the average ActionScript 3 developer, so it can be difficult to learn, use, and debug. Also, setting up a new project takes some time and considerable boilerplate code. See the Box2DFlash project page for examples.
Luckily, developer Zevan Rosser has wrapped the functionality of Box2DFlash into his QuickBox2D project. This takes care of that boilerplate code and eases the burden of some of the most common physics tasks. So we have QuickBox2D wrapping Box2DFlash, which in turn is a port of Box2D.
QuickBox2D is a mini library I created to work with Box2DFlash. The main purpose of this library is to significantly simplify instantiation of rigid bodies and provide a simple way to skin rigid bodies with custom graphics.
— Zevan Rosser, creator, QuickBox2D ActionScript 3 library
To understand the basics of this library, let's set up a simple demo project.
To get started:
The resulting Flash application is shown in Figure 2.
Figure 2. The Complete Flash CS4 Demo 'QuickBox2Ddemo_v1.swf'. Drag the three blocks with your mouse to play.
While incredibly simplistic, this little demo shows the power of physics for Flash. The blocks fly, fall, and bounce off each other in realistic ways. Even without any rules this demo is fun and thought-provoking for new game ideas.
In Figure 3, you can see how to set up a simple QuickBox2D project:
//Marks the right margin of code *******************************************************************
package
{
//--------------------------------------
// Imports
//--------------------------------------
import com.actionsnippet.qbox.QuickBox2D;
import com.actionsnippet.qbox.QuickObject;
import flash.display.MovieClip;
import flash.display.Sprite;
/**
* This metadata sets the size and framerate for the project.
*
**/
[SWF(width="600", height="300", backgroundColor="#cbcbcb", frameRate="30")]
//--------------------------------------
// Class
//--------------------------------------
public class QuickBox2DDemo extends Sprite
{
//--------------------------------------
// Properties
//--------------------------------------
//PUBLIC GETTER/SETTERS
/**
* Master Container for holding the physics bodies' visual parts
*
**/
private var _sim_movieclip : MovieClip;
/**
* Master Container for holding the physics bodies' data objects
*
**/
private var _sim_quickbox2D : QuickBox2D;
/**
* MovieClipSkins. A or B
*
* A) Published From Flash Builder 4: This project utilizes the './libs/StackZGame_assets_v1.swc' for graphics skinning
* B) Published From Flash CS4: This project utilizes library assets for graphics skinning
*
* Below when BlockSkin class is used, know that it is from that swc.
*
*/
/**
* Constants
*
**/
public static const PHYSICS_SCALE : Number = 1/30;
public static const PHYSICS_TIME_STEP : Number = 1/30;
//--------------------------------------
// Constructor
//--------------------------------------
/**
* Initialization of;
* The display list for visual elements
* The Physical world with properties to define how the world will behave
* The Blocks are added to the world with their own properties
* The world is 'started' so the interaction and 'fun' begins.
*
* <span class="hide">Any hidden comments go here.</span>
*
*/
public function QuickBox2DDemo ()
{
// SUPER
super ();
// CREATE A MOVIECLIP FOR THE PHYSICS WORLD
_sim_movieclip = new MovieClip ();
addChild (_sim_movieclip);
// CREATE THE PHYSICS WORLD (Partial list of parameters (default + description) is shown
_sim_quickbox2D = new QuickBox2D (_sim_movieclip,
{
// Rendering
debug : false, //false - Temporarily Render w/ Drawing API
simpleRender : true, //true - Toggles simple vs Custom Graphics
renderJoints : true, //true, - Toggles rendering of joints
// Physics
gravityX : 0, //0 - The x component of gravity
gravityY : 20, //20 - The y component of gravity
timeStep : PHYSICS_TIME_STEP, //1/60 - The Box2D time step.
iterations : 20, //20 - The Box2D iterations.
frim : false, //true, Toggles (Frame Rate
//Independent Movement).
// Misc
bounds : [-100, -100, 100, 100], //[-100, -100, 100, 100] - World Bounds
customMouse : false //false - For MouseEvents in 3D Worlds
});
// CREATE RIGID WALLS AROUND STAGE (NOT NEEDED, BUT CAN BE USEFUL)
_sim_quickbox2D.createStageWalls();
// SET DEFAULTS FOR MOVABLE OBJECTS (density != 0)
_sim_quickbox2D.setDefault
(
{
linearDamping : 1, //Friction applied from the 'air'
density : 1, //More Dense = Moves Slower
friction : 1 //Friction applied from colliding with other rigid bodies
}
);
// START THE PHYSICS & ENABLE MOUSE
_sim_quickbox2D.start(); //run an enterfame to power the engine
_sim_quickbox2D.mouseDrag(); //allow mouse to move all objects (with density != 0)
// CREATE SOME BLOCKS TO PLAY WITH
for (var blockIndex_uint : uint = 0; blockIndex_uint < 3; blockIndex_uint ++) {
_doCreateNewBlock (blockIndex_uint);
}
}
/**
* Create a new physical block with visual skin
*
* @param aBlockIndex_uint The index of the current block being created.
*
* @return void
*/
private function _doCreateNewBlock (aBlockIndex_uint : uint) : void
{
//CREATE MOVABLE OBJECT - A falling block at top, offscreen
var lastBlock_quickobject : QuickObject = _sim_quickbox2D.addBox
(
{
x : PHYSICS_SCALE * (100 + Math.random()*400), //Remember to Convert Pixels to Meters
y : PHYSICS_SCALE * (100 + Math.random()*200),
width : PHYSICS_SCALE * 100,
height : PHYSICS_SCALE * 100,
skin : BlockSkin, //Skin For Rigid Physics Body
draggable: true //User may manipulate the blocks with mouse
}
);
// THE SKIN IS INSTANTIATED, AND ACCESSIBLE AS 'userData'
// YOU CAN ALSO STORE ARBITRARY PROPERTIES ON 'userData' for whatever you need
(lastBlock_quickobject.userData as BlockSkin).character_mc.head_mc.gotoAndStop (aBlockIndex_uint+1); //show 3 faces
}
}
}
Figure 3. The Complete Flash CS4 Document Class 'QuickBox2DDemo.as'
The QuickBox2D Constructor accepts two parameters. First, this is passed as a
reference to the current object, the parent of the physics world. The physics
object's children. The second parameter is the flexible and powerful parameter
object. The parameter object contains high-level settings for the physics world. (See 'Partial list of parameters in Figure 3 for more information.)
Note that all Box2D distance units are in meters. To convert meters to pixels, use the following conversion:
var someDistanceInMeters_int : int = someDistanceInPixels_int / 30;
In my projects, I store the 30 in a constant to prevent typos:
var someDistanceInMeters_int : int = someDistanceInPixels_int / PHYSICS_SCALE;
To see a more complex example of this library, let's set up a game project called StackZ. In this game, the user drags a seesaw platform with the mouse to collect and stack falling boxes. The platform and the boxes react with realistic physics, creating a simple but engaging experience.
Not everything in a physics game is part of the physics simulation. Let's divide up the screen elements into two major groups:
| The non-physics elements are: | The physics elements are: |
|---|---|
|
|
The non-physics elements are laid out in the typical Flash fashion. They appear either behind the physics world (for example, the background) or in front of it (for example, the display text).
The physics elements will be created, skinned, and simulated using QuickBox2D. Most of the interactions will happen automatically as part of the simulation. That's the beauty of Box2DFlash. However some custom object interactions will be coded manually.
| The following are Box2DFlash built-in interactions: | The following are custom object interactions: |
|---|---|
|
|
Note: Much of using Box2DFlash is just creating objects and then letting the engine take care of the rest. It becomes quite empowering when you realize how easy it is to set up complex simulations. However some common functionality is trickier than you would think in physics-based games. Workarounds can be found on the Box2D Forum, on its Flash subsection, and by searching for solutions with Google. The following tasks are possible but tricky in Box2DFlash:
|
The project will use the Box2DFlash library for most of the heavy lifting. All custom code will be within the project's document class StackZGame.as.
To get started:
The resulting Flash application is shown in Figure 4.
Figure 4. The Complete Flash CS4 Game 'StackZGame_v2.swf'. Drag the black platform with the mouse to play.
In Figure 5, we see how to set up all the major parts of a physics-based game project.
//Marks the right margin of code *******************************************************************
package
{
//--------------------------------------
// Imports
//--------------------------------------
import Box2D.Dynamics.b2Body;
import com.actionsnippet.qbox.QuickBox2D;
import com.actionsnippet.qbox.QuickObject;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
/**
* This metadata sets the size and framerate for the project.
*
**/
[SWF(width="600", height="600", backgroundColor="#00ff00", frameRate="30")]
//--------------------------------------
// Class
//--------------------------------------
public class StackZGame extends Sprite
{
//--------------------------------------
// Properties
//--------------------------------------
//PUBLIC GETTER/SETTERS
/**
* Master container for holding the physics bodies visual parts
*
**/
private var _sim_movieclip : MovieClip;
/**
* Physics world and graphics. Arranged by depth.
* Tabbed-in here, means its a child of line above.
*
**/
private var _background : Background;
private var _world_sprite : Sprite;
private var _platform_quickobject : QuickObject;
private var _pedestal_quickobject : QuickObject;
private var _lastBlock_quickobject : QuickObject;
private var _platformArrows : PlatformArrows;
private var _finishLine : FinishLine;
private var _foreground : Foreground;
private var _scoreTextMC : ScoreTextMC;
private var _instructionsTextMC : InstructionsTextMC;
private var _border : Border;
private var _sim_quickbox2D : QuickBox2D;
/**
* Setup sound
*
**/
private var _blockCreation_timer : Timer;
private var _blockCreationSound : BlockCreationSound;
private var _blockFallenSound : BlockFallenSound;
/**
* Block-specific data
*
*/
private var _blocks_array : Array;
private var _blocksFallenTotal_uint : uint;
/**
* MovieClipSkins. A or B
*
* A) Published From Flash Builder 4: This project utilizes the './libs/StackZGame_assets_v1.swc' for graphics skinning
* B) Published From Flash CS4: This project utilizes library assets for graphics skinning
*
* Below when BlockSkin class is used, know that it is from that swc.
*
*/
/**
* Constants
*
**/
public static const PHYSICS_SCALE : Number = 1/30;
public static const PHYSICS_TIME_STEP : Number = 1/30;
public static const BLOCKS_FALLEN_TOTAL_ALLOWED : Number = 5;
private static const BLOCK_FALLEN_Y_LIMIT : Number = 590;
//--------------------------------------
// Constructor
//--------------------------------------
/**
* Setup the Layout. This is mostly visual, not physics setup yet.
*
* <span class="hide">Any hidden comments go here.</span>
*
*/
public function StackZGame ()
{
// SUPER
super ();
// CREATE WORLD
_world_sprite = new Sprite ();
addChild(_world_sprite);
// ----------------------------------------------------------
// POPULATE WORLD
// (from lowest visual depth to highest)
_background = new Background();
_world_sprite.addChild (_background);
//
_finishLine = new FinishLine ();
_world_sprite.addChild (_finishLine);
_finishLine.y = 300;
//
_platformArrows = new PlatformArrows ();
_world_sprite.addChild (_platformArrows);
//
var _foreground : MovieClip = new Foreground ();
_world_sprite.addChild (_foreground);
//
_instructionsTextMC = new InstructionsTextMC ();
_world_sprite.addChild (_instructionsTextMC);
_instructionsTextMC.y = 5;
_instructionsTextMC.textField.htmlText = "Mouse-drag the black pedestal to play! " +
"Create a tall pile before dropping " +
BLOCKS_FALLEN_TOTAL_ALLOWED + " blocks";
//
_scoreTextMC = new ScoreTextMC ();
_world_sprite.addChild (_scoreTextMC);
_scoreTextMC.y = _instructionsTextMC.y + _instructionsTextMC.height;
//
_border = new Border ();
addChild (_border);
// ----------------------------------------------------------
// CREATE SOUND
_blockCreationSound = new BlockCreationSound ();
_blockFallenSound = new BlockFallenSound ();
// LISTEN FOR THE RESTARTGAME MOUSE CLICK
addEventListener (MouseEvent.MOUSE_DOWN, _onMouseClickAnywhere);
// DO THE INITIAL RESTART - (AKA... the 'start')
_doRestartGame();
}
/**
* This is called initially, then upon each game restart
*
* Most of the visual are setup already, so this is primarily the physics setup
*
* @return void
*/
private function _doRestartGame () : void
{
// DELETE SIM MOVIECLIP IF EXISTING
if (_sim_movieclip != null) {
_sim_quickbox2D.destroy();
_world_sprite.removeChild(_sim_movieclip);
}
// CREATE SIM MOVIECLIP
_sim_movieclip = new MovieClip ();
_world_sprite.addChildAt (_sim_movieclip ,_world_sprite.getChildIndex(_finishLine));
// RESET FALLEN BLOCK COUNT
_blocksFallenTotal_uint = 0;
// CREATE AN ARRAY TO HOLD ALL BLOCKS
_blocks_array = new Array ();
// ----------------------------------------------------------
// CREATE THE PHYSICS WORLD (Partial list of parameters (default + description) is shown
_sim_quickbox2D = new QuickBox2D (_sim_movieclip,
{
// Rendering
debug : false, //false - Temporarily Render w/ Drawing API
simpleRender : true, //true - Toggles simple vs Custom Graphics
renderJoints : true, //true, - Toggles rendering of joints
// Physics
gravityX : 0, //0 - The x component of gravity
gravityY : 20, //20 - The y component of gravity
timeStep : PHYSICS_TIME_STEP, //1/60 - The Box2D time step.
iterations : 40, //20 - Calculation cycles per TimeStep
frim : false, //true - Toggles (Frame Rate
//Independent Movement).
// Misc
bounds : [-100, -100, 700, 700], //[-100, -100, 100, 100] - World Bounds
customMouse : false //false - For MouseEvents in 3D Worlds
});
// SET DEFAULTS FOR IMMOVABLE OBJECTS (density = 0)
_sim_quickbox2D.setDefault
(
{
linearDamping : 1, //Friction applied from the 'air'
density : 0, //More Dense = Moves Slower, 0 means immovable
friction : 1 //Friction applied from colliding with other rigid bodies
}
);
// CREATE IMMOVABLE OBJECT - The pedestal at the bottom of the screen.
_pedestal_quickobject = _sim_quickbox2D.addBox
(
{
x : PHYSICS_SCALE * (_border.width/2), //Remember to Convert Pixels to Meters
y : PHYSICS_SCALE * (525),
width : PHYSICS_SCALE * 10,
height : PHYSICS_SCALE * 10,
skin : PedestalSkin //Skin For Rigid Physics Body
}
);
// SET DEFAULTS FOR MOVABLE OBJECTS (density != 0)
_sim_quickbox2D.setDefault
(
{
linearDamping : 1, //Friction applied from the 'air'
density : 1, //More Dense = Moves Slower
friction : 1 //Friction applied from colliding with other rigid bodies
}
);
// CREATE MOVABLE OBJECT - The platform at the bottom of the screen, above the pedestal
_platform_quickobject = _sim_quickbox2D.addBox
(
{
x : PHYSICS_SCALE * (_border.width/2), //Remember to Convert Pixels to Meters
y : PHYSICS_SCALE * (520),
width : PHYSICS_SCALE * 300,
height : PHYSICS_SCALE * 40,
skin : PlatformSkin //Skin For Rigid Physics Body
}
);
// MATCH THE VISUAL-ONLY (NON-PHYSICS) ARROW GRAPHICS TO THE PLATFORM
// I didn't want the block to bounce off the arrows
_platformArrows.x = _platform_quickobject.userData.x;
_platformArrows.y = _platform_quickobject.userData.y;
// CREATE A JOINT - The platform balances on top of the pedestal
_sim_quickbox2D.addJoint
(
{
type: QuickBox2D.REVOLUTE,
a:_platform_quickobject.body,
b:_pedestal_quickobject.body,
collideConnected:false,
lowerAngle:-Math.PI/6,
upperAngle:Math.PI/6,
enableLimit:true
}
);
addEventListener(Event.ENTER_FRAME, _onEnterFrame);
// START THE PHYSICS
_sim_quickbox2D.start(); //run an enterfame to power the engine
_sim_quickbox2D.mouseDrag(); //allow mouse to move all objects (with density != 0)
// SHOW TEXT
_doUpdateScoreText ();
// SETUP AUTO-BLOCK-CREATION
if (!_blockCreation_timer) {
_blockCreation_timer = new Timer (4000);
_blockCreation_timer.addEventListener(TimerEvent.TIMER, _onBlockCreationTimer);
}
_blockCreation_timer.start();
// CREATE ONE BLOCK IMMEDIATLY
_doCreateNewBlock();
}
/**
* Create a new block off the top of the screen. It will fall with gravity.
*
* @return void
*/
private function _doCreateNewBlock () : void
{
// PLAY SOUND
_blockCreationSound.play();
// CREATE MOVABLE OBJECT - A falling block at top, off screen
_lastBlock_quickobject = _sim_quickbox2D.addBox (
{
x : PHYSICS_SCALE * (_border.width/2 - Math.random()*50 + Math.random()*50),
y : PHYSICS_SCALE * (0),
width : PHYSICS_SCALE * 50, //Remember to convert pixels to meters with PHYSICS_SCALE
height : PHYSICS_SCALE * 50,
skin : BlockSkin, //Skin For rigid physics body
draggable: false //User may only manipulate the platform, not the blocks
}
);
// KEEP A LIST OF BOXES
_blocks_array.push (_lastBlock_quickobject);
// THE SKIN IS INSTANTIATED, AND ACCESSIBLE AS 'userData'
// YOU CAN ALSO STORE ARBITRARY PROPERTIES ON 'userData' for whatever you need
(_lastBlock_quickobject.userData as BlockSkin).character_mc.head_mc.gotoAndStop (1); //show a 'happy' face
}
/**
* Count each time a block falls offscreen. This will cause a game loss eventually.
*
* @return void
*/
private function _doUpdateBlockFallenTotal () : void
{
// COUNT UP
_blocksFallenTotal_uint++;
_doUpdateScoreText ();
// CHECK FOR GAME OVER
if (_blocksFallenTotal_uint >= BLOCKS_FALLEN_TOTAL_ALLOWED) {
_doEndGameAsLoser();
}
}
/**
* Remove blocks that fall offscreen and increment counter
*
* @param aEvent QuickObject which has fallen offscreen
*
* @return void
*/
private function _doHandleBlockOffScreen (aQuickObject : QuickObject) : void
{
// PLAY A SOUND
_blockFallenSound.play();
// DESTROY OBJECT
aQuickObject.destroy();
// REMOVE FROM CUSTOM ARRAY
_blocks_array.splice (_blocks_array.indexOf(aQuickObject),1);
// CHANGE DISPLAY TEXT
_doUpdateBlockFallenTotal ();
}
/**
* Show the 'You Won!' text and stop the game physics from running.
*
* @return void
*/
private function _doEndGameAsWinner () : void
{
_scoreTextMC.textField.htmlText = "Blocks Dropped Offscreen: " +
_blocksFallenTotal_uint + " of " +
BLOCKS_FALLEN_TOTAL_ALLOWED +
" Allow<BR><BR><BR><P ALIGN='CENTER'><FONT SIZE = '40'>YOU WON!</FONT></P><FONT SIZE = '10'><BR>Mouse-click anywhere above the " +
"'Finish Line' " + "to restart the game</FONT>ed";
_doStopGamePermanently ();
}
/**
* Show the 'You Lost!' text and stop the game physics from running.
*
* @return void
*/
private function _doEndGameAsLoser () : void
{
_scoreTextMC.textField.htmlText = "Blocks Dropped Offscreen: " +
_blocksFallenTotal_uint + " of " +
BLOCKS_FALLEN_TOTAL_ALLOWED +
" Allow<BR><BR><BR><P ALIGN='CENTER'><FONT SIZE = '40'>YOU LOST!</FONT></P><FONT SIZE = '10'><BR>Mouse-click anywhere above the " +
"'Finish Line' " + "to restart the game</FONT>ed";
_doStopGamePermanently();
}
/**
* Show the # of blocks which have fallen. Too many fallen means game over.
*
* @return void
*/
private function _doUpdateScoreText () : void
{
_scoreTextMC.textField.htmlText = "Blocks Dropped Offscreen: " + _blocksFallenTotal_uint + " of " + BLOCKS_FALLEN_TOTAL_ALLOWED + " Allowed";
}
/**
* Stop the game physics from running and other repeated tasks
*
* @return void
*/
private function _doStopGamePermanently () : void
{
_sim_quickbox2D.destroy();
removeEventListener (Event.ENTER_FRAME, _onEnterFrame);
_sim_quickbox2D.stop();
_blockCreation_timer.reset();
_blockCreation_timer.stop();
}
//--------------------------------------
// Events
//--------------------------------------
/**
* Capture Event: Event.ENTER_FRAME, 30 times per second, this code executes my custom code
*
* @param aEvent Event
*
* @return void
*/
private function _onEnterFrame (aEvent : Event) : void
{
// MATCH THE VISUAL-ONLY (NON-PHYSICS) ARROWS TO THE PLATFORM
_platformArrows.rotation = _platform_quickobject.userData.rotation;
// LOOP THROUGH BLOCKS FOR THREE UNIQUE CHECKS (A,B,C)
for each (var quickObject : QuickObject in _blocks_array) {
// A) DID BOX FALL INTO PLAY - Necessary for 'victory' detection
if (!quickObject.userData.isInPlay_boolean &&
Math.abs(quickObject.body.m_linearVelocity.y) > .1 ) {
quickObject.userData.isInPlay_boolean = true;
}
// B) DID BOX FALL OFFSCREEN? - A bad thing for user
if (quickObject.y / PHYSICS_SCALE > BLOCK_FALLEN_Y_LIMIT) {
_doHandleBlockOffScreen(quickObject);
}
// ----------------------------------------------------------
// CONDITIONS FOR VICTORY - Is there a 'stack' of contiguously touching boxes
// - with at least one above the finish line?
// - **The solution below is simple, but not perfect**
// ----------------------------------------------------------
// C) Is there at least one box that meets ALL of the following criterion
// 1. Is above the Finish Line
// 2. Is 'in play'
// 3. Is moving very slowly (approximatly non-moving)
// 4. Touching at least one other block (this doesn't prove its in a 'stack' but it helps)
//
// ----------------------------------------------------------
if ( (quickObject.y / PHYSICS_SCALE) < _finishLine.y &&
quickObject.userData.isInPlay_boolean &&
Math.abs(quickObject.body.m_linearVelocity.y) < 0.4 ) {
//IS IT COLLIDING WITH ANOTHER BLOCK (NOT ITSELF)
for each (var quickObject2 : QuickObject in _blocks_array) {
if (quickObject != quickObject2) {
if ((quickObject.userData as MovieClip).hitTestObject (quickObject2.userData) ) {
_doEndGameAsWinner ();
}
}
}
}
}
}
/**
* Capture Event: TimerEvent.TIMER, Every X seconds, create a new block
*
* @param aEvent TimerEvent
*
* @return void
*/
private function _onBlockCreationTimer (aEvent : TimerEvent) : void
{
_doCreateNewBlock ();
}
/**
* Capture Event: MouseEvent.CLICK, When user clicks on the screen, restart the game.
*
* @param aEvent MouseEvent
*
* @return void
*/
private function _onMouseClickAnywhere (aEvent : MouseEvent) : void
{
if (aEvent.stageY < _finishLine.y) {
_doRestartGame();
}
}
}
}
Figure 5. Complete Flash CS4 document class, StackZGame.as
Fantastic! In just about 400 lines (500 with comments) of ActionScript 3 we have a fully functioning physics-based game. This would not be possible without using Box2D-based libraries to ease our development.
The quality of casual, browser-based games is now very high and the public is beginning to view these as professional products. Physics-based games allow players to be creative with open-ended game solutions and they key into the users' natural ability to predict the smooth motion of physical objects. This adds needed polish and fun to gaming.
— Erin Catto, creator, Box2D physics library
We now see the value of physics to create fun, new styles of gameplay. By taking advantage of mature, powerful physics libraries such as Box2DFlash and QuickBox2D, teams can rapidly create unique and engaging gameplay. While thankfully much of the physics interactions are "automatic," sometimes seemingly simple tasks can be tricky to complete. Together with the downloadable examples and the explanation in this article, the time is now to add physics-based gaming to your Flash Platform development repertoire.
I want to offer a special thanks to Autumn Rain Turkel of TangledDreams who created all the art for the StackZ game, and to all the developers and community leaders who provided valuable insight and expertise for this article.
Samuel Asher Rivello is the principal of Rivello Multimedia Consulting (RMC). RMC’s Flash and Flex services include software architecture, consulting, development, and training. Sam has a decade of experience creating games and applications, and is currently traveling the globe to collaborate with top companies.