Interactive Designer and Developer
Collider Exhibit Series

Box2DFlash - Falling Text

I'm so excited that I finally got to work on some experimental Flash at my professional employment. It is a nice change of pace to push an idea to the limits...and then some. In fact, I'm still not done working on the possibilities. This was only the starting point. Making text fall. Tie it into the Box2DFlash Physics Engine.

I want to give yet another shout out to Emanuele Feronato. If you are looking at this code, and are completely lost, he has EXCELLENT tutorials to get you started. Thats where I ended up taking my first steps in Box2DFlash.

Now in the guise of learning. I don't intend on going too indepth with the code...there is a lot going on. But hopefully, by breaking it down into phases, you can understand my building process. Something like this isn't accomplished in one chunk of code. It is build up by steps. At least the way I code.

embedfontThere is one important element I need to mention.

EMBEDDING FONT: In the Library in the FLA, you need to embed the font via "New Font..." in the Library options. I embedded Verdana for this example. Because if you use a dynamic textfield to animate (especially rotations) the font could randomly just disappear on you. So, this fixes that problem.

So here is the game plan:

  1. Make a base Box2DFlash file
  2. add in falling boxes
  3. add in dynamic text
  4. make the text match the orientation of the boxes
  5. make the boxes match the size of the text
  6. display only the text

Simple, right? Let us begin.

And here is a zip with FLA and AS files to follow along.

The Base

box2d_textfalls.v1

So we start with just a build of Box2DFlash. I've just added a floor and a circle to bounce boxes off of. I'll add in my copy of Box2DFlash into the zip. There is one thing to remember when figuring out placement and measurements in Box2DFlash. The timing and physics is calculated not using the normal frame rate. It need to be calculated by some other way, time I believe (just not frame). By default it seems like the X and Y measurements are figured out by taking the value you want it to be in pixels and just dividing by 30. So if you want something 1024 pixels it'll be 34.133 in Box2DFlash.

package {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFormat;
        import flash.events.Event;
 
        import Box2D.Dynamics.*;
        import Box2D.Collision.*;
        import Box2D.Collision.Shapes.*;
        import Box2D.Common.Math.*;
 
        public class TextFalls extends Sprite {
                public var the_world:b2World;
                public var physScale:Number=30;
                public var final_body:b2Body;
                public var the_body:b2BodyDef;
                public var the_box:b2PolygonDef;
                public var the_circle:b2CircleDef;
                public var environment:b2AABB = new b2AABB();
                public var gravity:b2Vec2=new b2Vec2(0.0,10.0);
 
                public function TextFalls() {
 
                        environment.lowerBound.Set(-100.0, -100.0);
                        environment.upperBound.Set(100.0, 100.0);
                        the_world=new b2World(environment,gravity,true);
 
                        buildWalls();
 
                        addEventListener(Event.ENTER_FRAME, on_enter_frame);
 
                }
 
                public function buildWalls() {
                        trace("Building Walls");
                        //This Turns on The Ability to View Where the Physics Blockades are (best to get used to the spacing)
                        var debug_draw:b2DebugDraw = new b2DebugDraw();
                        var debug_sprite:Sprite = new Sprite();
                        addChild(debug_sprite);
                        debug_draw.m_sprite=debug_sprite;
                        debug_draw.m_drawScale=30;
                        debug_draw.m_fillAlpha=0.5;
                        debug_draw.m_lineThickness=1;
                        debug_draw.m_drawFlags=b2DebugDraw.e_shapeBit;
                        the_world.SetDebugDraw(debug_draw);
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 2 / physScale, 768 / physScale);//physScale is used to make calculating time based physics and not frame based.
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(400 / physScale, 20 / physScale);
                        the_box.friction=0.3;
                        the_box.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 5 / physScale, 768 / 2 / physScale);
                        the_circle = new b2CircleDef();
                        the_circle.radius=3.0;
                        the_circle.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_circle);
                        final_body.SetMassFromShapes();
 
                }
 
                public function on_enter_frame(e:Event) {
                        the_world.Step(1/30, 10);
                }
        }
}

Adding Blocks

box2d_textfalls.v2

Now we need some physics items. Since text has a mostly rectangular shape. Lets start with boxes.

package {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFormat;
        import flash.events.Event;
        import flash.utils.Timer;
        import flash.events.TimerEvent;
 
        import Box2D.Dynamics.*;
        import Box2D.Collision.*;
        import Box2D.Collision.Shapes.*;
        import Box2D.Common.Math.*;
 
        public class TextFalls extends Sprite {
                public var the_world:b2World;
                public var physScale:Number=30;
                public var final_body:b2Body;
                public var the_body:b2BodyDef;
                public var the_box:b2PolygonDef;
                public var the_circle:b2CircleDef;
                public var environment:b2AABB = new b2AABB();
                public var gravity:b2Vec2=new b2Vec2(0.0,10.0);
 
                public var dropTextTime:Timer;
 
                public function TextFalls() {
 
                        environment.lowerBound.Set(-100.0, -100.0);
                        environment.upperBound.Set(100.0, 100.0);
                        the_world=new b2World(environment,gravity,true);
 
                        buildWalls();
 
                        addEventListener(Event.ENTER_FRAME, on_enter_frame);
 
                        dropTextTime=new Timer(1000, 0);
                        dropTextTime.addEventListener(TimerEvent.TIMER, newText);
                        dropTextTime.start();
                }
 
                public function buildWalls() {
                        trace("Building Walls");
                        //This Turns on The Ability to View Where the Physics Blockades are (best to get used to the spacing)
                        var debug_draw:b2DebugDraw = new b2DebugDraw();
                        var debug_sprite:Sprite = new Sprite();
                        addChild(debug_sprite);
                        debug_draw.m_sprite=debug_sprite;
                        debug_draw.m_drawScale=30;
                        debug_draw.m_fillAlpha=0.5;
                        debug_draw.m_lineThickness=1;
                        debug_draw.m_drawFlags=b2DebugDraw.e_shapeBit;
                        the_world.SetDebugDraw(debug_draw);
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 2 / physScale, 768 / physScale);//physScale is used to make calculating time based physics and not frame based.
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(400 / physScale, 20 / physScale);
                        the_box.friction=0.3;
                        the_box.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 5 / physScale, 768 / 2 / physScale);
                        the_circle = new b2CircleDef();
                        the_circle.radius=3.0;
                        the_circle.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_circle);
                        final_body.SetMassFromShapes();
 
                }
 
                public function newText(evt:TimerEvent):void{
                        var final_body:b2Body;
                        var the_body:b2BodyDef;
                        var the_box:b2PolygonDef;
                        the_body = new b2BodyDef();
                        the_body.position.Set(Math.random()*6.6+10, -1);
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(1, 1);
                        the_box.friction=1;
                        the_box.density=.9;
                        the_box.restitution=.2;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
                }
 
                public function on_enter_frame(evt:Event) {
                        the_world.Step(1/30, 10);
                }
        }
}

Keep Memory Clean

box2d_textfalls.v3

Now, I don't want the falling block to exist forever. So in case they do fall off of the floor, I want to remove the items from the Flash.

package {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFormat;
        import flash.events.Event;
        import flash.utils.Timer;
        import flash.events.TimerEvent;
 
        import Box2D.Dynamics.*;
        import Box2D.Collision.*;
        import Box2D.Collision.Shapes.*;
        import Box2D.Common.Math.*;
 
        public class TextFalls extends Sprite {
                public var the_world:b2World;
                public var physScale:Number=30;
                public var final_body:b2Body;
                public var the_body:b2BodyDef;
                public var the_box:b2PolygonDef;
                public var the_circle:b2CircleDef;
                public var environment:b2AABB = new b2AABB();
                public var gravity:b2Vec2=new b2Vec2(0.0,10.0);
 
                public var dropTextTime:Timer;
                public var blockTrackingArray:Array = new Array();
 
                public function TextFalls() {
 
                        environment.lowerBound.Set(-100.0, -100.0);
                        environment.upperBound.Set(100.0, 100.0);
                        the_world=new b2World(environment,gravity,true);
 
                        buildWalls();
 
                        addEventListener(Event.ENTER_FRAME, on_enter_frame);
 
                        dropTextTime=new Timer(1000, 0);
                        dropTextTime.addEventListener(TimerEvent.TIMER, newText);
                        dropTextTime.start();
                }
 
                public function buildWalls() {
                        trace("Building Walls");
                        //This Turns on The Ability to View Where the Physics Blockades are (best to get used to the spacing)
                        var debug_draw:b2DebugDraw = new b2DebugDraw();
                        var debug_sprite:Sprite = new Sprite();
                        addChild(debug_sprite);
                        debug_draw.m_sprite=debug_sprite;
                        debug_draw.m_drawScale=30;
                        debug_draw.m_fillAlpha=0.5;
                        debug_draw.m_lineThickness=1;
                        debug_draw.m_drawFlags=b2DebugDraw.e_shapeBit;
                        the_world.SetDebugDraw(debug_draw);
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 2 / physScale, 768 / physScale);//physScale is used to make calculating time based physics and not frame based.
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(400 / physScale, 20 / physScale);
                        the_box.friction=0.3;
                        the_box.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 5 / physScale, 768 / 2 / physScale);
                        the_circle = new b2CircleDef();
                        the_circle.radius=3.0;
                        the_circle.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_circle);
                        final_body.SetMassFromShapes();
 
                }
 
                public function newText(evt:TimerEvent):void{
                        var final_body:b2Body;
                        var the_body:b2BodyDef;
                        var the_box:b2PolygonDef;
                        the_body = new b2BodyDef();
                        the_body.position.Set(Math.random()*6.6+10, -1);
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(1, 1);
                        the_box.friction=1;
                        the_box.density=.9;
                        the_box.restitution=.2;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
                        blockTrackingArray.push(final_body);
 
                }
 
                public function on_enter_frame(evt:Event) {
                        the_world.Step(1/30, 10);
 
                        var detroyAt:Array = new Array();
                        var totalBlocks = blockTrackingArray.length;
                        for(var b = 0; b < totalBlocks; ++b){
                                if(blockTrackingArray[b].GetPosition().y > 768 / physScale){ //Kills Block if it fall past the screen.
                                        the_world.DestroyBody(blockTrackingArray[b]);
                                        detroyAt.push(b);
                                }
                        }
 
                        for(var intd = detroyAt.length-1; intd >= 0; --intd){
                                blockTrackingArray.splice(detroyAt[intd], 1);
                                detroyAt.pop();
                        }
 
                }
        }
}

Adding Text

box2d_textfalls.v4

Now its time to add some text. I'm building a long string of 'lorem ipsum' into an array. As the text is created, it just moves to the next word. This is where you can change the content being pulled into the page.

package {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFormat;
        import flash.events.Event;
        import flash.utils.Timer;
        import flash.events.TimerEvent;
 
        import Box2D.Dynamics.*;
        import Box2D.Collision.*;
        import Box2D.Collision.Shapes.*;
        import Box2D.Common.Math.*;
 
        public class TextFalls extends Sprite {
                public var the_world:b2World;
                public var physScale:Number=30;
                public var final_body:b2Body;
                public var the_body:b2BodyDef;
                public var the_box:b2PolygonDef;
                public var the_circle:b2CircleDef;
                public var environment:b2AABB = new b2AABB();
                public var gravity:b2Vec2=new b2Vec2(0.0,10.0);
 
                public var dropTextTime:Timer;
                public var blockTrackingArray:Array = new Array();
                public var labelTxt:TextField = new TextField();
                public var labelTrackingArray:Array = new Array();
                public var wordsArray:Array = new Array();
                public var slot=0;
                public var Text:String="Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
 
                public function TextFalls() {
 
                        environment.lowerBound.Set(-100.0, -100.0);
                        environment.upperBound.Set(100.0, 100.0);
                        the_world=new b2World(environment,gravity,true);
 
                        buildWalls();
 
                        addEventListener(Event.ENTER_FRAME, on_enter_frame);
 
                        dropTextTime=new Timer(1000,0);
                        dropTextTime.addEventListener(TimerEvent.TIMER, newText);
                        dropTextTime.start();
 
                        wordsArray=Text.split(" ");
                }
 
                public function buildWalls() {
                        trace("Building Walls");
                        //This Turns on The Ability to View Where the Physics Blockades are (best to get used to the spacing)
                        var debug_draw:b2DebugDraw = new b2DebugDraw();
                        var debug_sprite:Sprite = new Sprite();
                        addChild(debug_sprite);
                        debug_draw.m_sprite=debug_sprite;
                        debug_draw.m_drawScale=30;
                        debug_draw.m_fillAlpha=0.5;
                        debug_draw.m_lineThickness=1;
                        debug_draw.m_drawFlags=b2DebugDraw.e_shapeBit;
                        the_world.SetDebugDraw(debug_draw);
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 2 / physScale, 768 / physScale);//physScale is used to make calculating time based physics and not frame based.
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(400 / physScale, 20 / physScale);
                        the_box.friction=0.3;
                        the_box.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 5 / physScale, 768 / 2 / physScale);
                        the_circle = new b2CircleDef();
                        the_circle.radius=3.0;
                        the_circle.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_circle);
                        final_body.SetMassFromShapes();
 
                }
 
                private function NewTextLabel():void {
                        labelTxt = new TextField();
                        labelTxt.autoSize=TextFieldAutoSize.LEFT;
                        labelTxt.cacheAsBitmap=true;
                        labelTxt.embedFonts=true;
                        labelTxt.x=-100;
 
                        var format:TextFormat = new TextFormat();
                        format.font="Verdana";
                        format.color=0xFFFFFF;
                        if (wordsArray[slot].length==0) {
                                ++slot;
                        }
                        if (slot>=wordsArray.length-1) {
                                slot=0;
                        }
                        labelTxt.text=wordsArray[slot];
                        format.size=20;
                        labelTxt.defaultTextFormat=format;
                        labelTxt.text=wordsArray[slot];
                        ++slot;
                }
 
                public function newText(evt:TimerEvent):void {
                        NewTextLabel();
                        addChild(labelTxt);
                        labelTrackingArray.push(labelTxt);
 
                        var final_body:b2Body;
                        var the_body:b2BodyDef;
                        var the_box:b2PolygonDef;
                        the_body = new b2BodyDef();
                        the_body.position.Set(Math.random()*6.6+10, -1);
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(1, 1);
                        the_box.friction=1;
                        the_box.density=.9;
                        the_box.restitution=.2;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
                        blockTrackingArray.push(final_body);
 
                }
 
                public function on_enter_frame(evt:Event) {
                        the_world.Step(1/30, 10);
 
                        var detroyAt:Array = new Array();
                        var totalBlocks=blockTrackingArray.length;
                        for (var b = 0; b < totalBlocks; ++b) {
                                if (blockTrackingArray[b].GetPosition().y>768/physScale) {//Kills Block if it fall past the screen.
                                        the_world.DestroyBody(blockTrackingArray[b]);
                                        removeChild(labelTrackingArray[b]);
                                        detroyAt.push(b);
                                } else {
                                        var bodyRotation:Number=blockTrackingArray[b].GetAngle();
                                        labelTrackingArray[b].rotation = bodyRotation  * (180/Math.PI) % 360;
                                        labelTrackingArray[b].x = (blockTrackingArray[b].GetPosition().x * physScale);
                                        labelTrackingArray[b].y = (blockTrackingArray[b].GetPosition().y * physScale);
                                }
                        }
 
                        for (var d = detroyAt.length-1; d >= 0; --d) {
                                blockTrackingArray.splice(detroyAt[d], 1);
                                labelTrackingArray.splice(detroyAt[d], 1);
                                detroyAt.pop();
                        }
 
                }
        }
}

Scale Physics Boxes

box2d_textfallsv.4b

Now the physics boxes get rescaled to match the width and height of the text.

package {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFormat;
        import flash.events.Event;
        import flash.utils.Timer;
        import flash.events.TimerEvent;
 
        import Box2D.Dynamics.*;
        import Box2D.Collision.*;
        import Box2D.Collision.Shapes.*;
        import Box2D.Common.Math.*;
 
        public class TextFalls extends Sprite {
                public var the_world:b2World;
                public var physScale:Number=30;
                public var final_body:b2Body;
                public var the_body:b2BodyDef;
                public var the_box:b2PolygonDef;
                public var the_circle:b2CircleDef;
                public var environment:b2AABB = new b2AABB();
                public var gravity:b2Vec2=new b2Vec2(0.0,10.0);
 
                public var dropTextTime:Timer;
                public var blockTrackingArray:Array = new Array();
                public var labelTxt:TextField = new TextField();
                public var labelTrackingArray:Array = new Array();
                public var wordsArray:Array = new Array();
                public var slot=0;
                public var Text:String="Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
 
                public function TextFalls() {
 
                        environment.lowerBound.Set(-100.0, -100.0);
                        environment.upperBound.Set(100.0, 100.0);
                        the_world=new b2World(environment,gravity,true);
 
                        buildWalls();
 
                        addEventListener(Event.ENTER_FRAME, on_enter_frame);
 
                        dropTextTime=new Timer(1000,0);
                        dropTextTime.addEventListener(TimerEvent.TIMER, newText);
                        dropTextTime.start();
 
                        wordsArray=Text.split(" ");
                }
 
                public function buildWalls() {
                        trace("Building Walls");
                        //This Turns on The Ability to View Where the Physics Blockades are (best to get used to the spacing)
                        var debug_draw:b2DebugDraw = new b2DebugDraw();
                        var debug_sprite:Sprite = new Sprite();
                        addChild(debug_sprite);
                        debug_draw.m_sprite=debug_sprite;
                        debug_draw.m_drawScale=30;
                        debug_draw.m_fillAlpha=0.5;
                        debug_draw.m_lineThickness=1;
                        debug_draw.m_drawFlags=b2DebugDraw.e_shapeBit;
                        the_world.SetDebugDraw(debug_draw);
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 2 / physScale, 768 / physScale);//physScale is used to make calculating time based physics and not frame based.
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(400 / physScale, 20 / physScale);
                        the_box.friction=0.3;
                        the_box.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 5 / physScale, 768 / 2 / physScale);
                        the_circle = new b2CircleDef();
                        the_circle.radius=3.0;
                        the_circle.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_circle);
                        final_body.SetMassFromShapes();
 
                }
 
                private function NewTextLabel():void {
                        labelTxt = new TextField();
                        labelTxt.autoSize=TextFieldAutoSize.LEFT;
                        labelTxt.cacheAsBitmap=true;
                        labelTxt.embedFonts=true;
                        labelTxt.x=-100;
 
                        var format:TextFormat = new TextFormat();
                        format.font="Verdana";
                        format.color=0xFFFFFF;
                        if (wordsArray[slot].length==0) {
                                ++slot;
                        }
                        if (slot>=wordsArray.length-1) {
                                slot=0;
                        }
                        labelTxt.text=wordsArray[slot];
                        format.size=20;
                        labelTxt.defaultTextFormat=format;
                        labelTxt.text=wordsArray[slot];
                        ++slot;
                }
 
                public function newText(evt:TimerEvent):void {
                        NewTextLabel();
                        addChild(labelTxt);
                        labelTrackingArray.push(labelTxt);
 
                        var final_body:b2Body;
                        var the_body:b2BodyDef;
                        var the_box:b2PolygonDef;
                        the_body = new b2BodyDef();
                        the_body.position.Set(Math.random()*6.6+10, -1);
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(labelTxt.width/physScale/2, labelTxt.height/physScale/2);
                        the_box.friction=1;
                        the_box.density=.9;
                        the_box.restitution=.2;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
                        blockTrackingArray.push(final_body);
 
                }
 
                public function on_enter_frame(evt:Event) {
                        the_world.Step(1/30, 10);
 
                        var detroyAt:Array = new Array();
                        var totalBlocks=blockTrackingArray.length;
                        for (var b = 0; b < totalBlocks; ++b) {
                                if (blockTrackingArray[b].GetPosition().y>768/physScale) {//Kills Block if it fall past the screen.
                                        the_world.DestroyBody(blockTrackingArray[b]);
                                        removeChild(labelTrackingArray[b]);
                                        detroyAt.push(b);
                                } else {
                                        var bodyRotation:Number=blockTrackingArray[b].GetAngle();
                                        labelTrackingArray[b].rotation = bodyRotation  * (180/Math.PI) % 360;
                                        labelTrackingArray[b].x = (blockTrackingArray[b].GetPosition().x * physScale);
                                        labelTrackingArray[b].y = (blockTrackingArray[b].GetPosition().y * physScale);
                                }
                        }
 
                        for (var d = detroyAt.length-1; d >= 0; --d) {
                                blockTrackingArray.splice(detroyAt[d], 1);
                                labelTrackingArray.splice(detroyAt[d], 1);
                                detroyAt.pop();
                        }
 
                }
        }
}

Re-Positioning Text

box2d_textfalls.v5

Time to move the text into the block area of the physics item.

package {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFormat;
        import flash.events.Event;
        import flash.utils.Timer;
        import flash.events.TimerEvent;
 
        import Box2D.Dynamics.*;
        import Box2D.Collision.*;
        import Box2D.Collision.Shapes.*;
        import Box2D.Common.Math.*;
 
        public class TextFalls extends Sprite {
                public var the_world:b2World;
                public var physScale:Number=30;
                public var final_body:b2Body;
                public var the_body:b2BodyDef;
                public var the_box:b2PolygonDef;
                public var the_circle:b2CircleDef;
                public var environment:b2AABB = new b2AABB();
                public var gravity:b2Vec2=new b2Vec2(0.0,10.0);
 
                public var dropTextTime:Timer;
                public var blockTrackingArray:Array = new Array();
                public var labelTxt:TextField = new TextField();
                public var labelTrackingArray:Array = new Array();
                public var wordsArray:Array = new Array();
                public var slot=0;
                public var Text:String="Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
 
                public var spriteArray:Array = new Array();
                public var holderSprite:Sprite = new Sprite();
 
                public function TextFalls() {
 
                        environment.lowerBound.Set(-100.0, -100.0);
                        environment.upperBound.Set(100.0, 100.0);
                        the_world=new b2World(environment,gravity,true);
 
                        buildWalls();
 
                        addEventListener(Event.ENTER_FRAME, on_enter_frame);
 
                        dropTextTime=new Timer(1000,0);
                        dropTextTime.addEventListener(TimerEvent.TIMER, newText);
                        dropTextTime.start();
 
                        wordsArray=Text.split(" ");
                }
 
                public function buildWalls() {
                        trace("Building Walls");
                        //This Turns on The Ability to View Where the Physics Blockades are (best to get used to the spacing)
                        var debug_draw:b2DebugDraw = new b2DebugDraw();
                        var debug_sprite:Sprite = new Sprite();
                        addChild(debug_sprite);
                        debug_draw.m_sprite=debug_sprite;
                        debug_draw.m_drawScale=30;
                        debug_draw.m_fillAlpha=0.5;
                        debug_draw.m_lineThickness=1;
                        debug_draw.m_drawFlags=b2DebugDraw.e_shapeBit;
                        the_world.SetDebugDraw(debug_draw);
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 2 / physScale, 768 / physScale);//physScale is used to make calculating time based physics and not frame based.
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(400 / physScale, 20 / physScale);
                        the_box.friction=0.3;
                        the_box.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 5 / physScale, 768 / 2 / physScale);
                        the_circle = new b2CircleDef();
                        the_circle.radius=3.0;
                        the_circle.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_circle);
                        final_body.SetMassFromShapes();
 
                }
 
                private function NewTextLabel():void {
 
                        labelTxt = new TextField();
                        labelTxt.autoSize=TextFieldAutoSize.LEFT;
                        labelTxt.cacheAsBitmap=true;
                        labelTxt.embedFonts=true;
 
                        var format:TextFormat = new TextFormat();
                        format.font="Verdana";
                        format.color=0xFFFFFF;
                        if (wordsArray[slot].length==0) {
                                ++slot;
                        }
                        if (slot>=wordsArray.length-1) {
                                slot=0;
                        }
                        labelTxt.text=wordsArray[slot];
                        format.size=20;
                        labelTxt.defaultTextFormat=format;
                        labelTxt.text=wordsArray[slot];
                        ++slot;
                }
 
                public function newText(evt:TimerEvent):void {
                        NewTextLabel();
                        holderSprite = new Sprite();
                        addChild(holderSprite);
                        holderSprite.addChild(labelTxt);
                        labelTxt.x=holderSprite.x-labelTxt.width/2;
                        labelTxt.y=holderSprite.y-labelTxt.height/2;
                        holderSprite.x = -1000;
                        holderSprite.y = -1000;
 
                        spriteArray.push(holderSprite);
                        labelTrackingArray.push(labelTxt);
 
                        var final_body:b2Body;
                        var the_body:b2BodyDef;
                        var the_box:b2PolygonDef;
                        the_body = new b2BodyDef();
                        the_body.position.Set(Math.random()*6.6+10, -1);
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(labelTxt.width/physScale/2, labelTxt.height/physScale/2);
                        the_box.friction=1;
                        the_box.density=.9;
                        the_box.restitution=.2;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
                        blockTrackingArray.push(final_body);
 
                }
 
                public function on_enter_frame(evt:Event) {
                        the_world.Step(1/30, 10);
 
                        var detroyAt:Array = new Array();
                        var totalBlocks=blockTrackingArray.length;
 
                        for (var b = 0; b < totalBlocks; ++b) {
                                if (blockTrackingArray[b].GetPosition().y>768/physScale) {//Kills Block if it fall past the screen.
                                        spriteArray[b].removeChild(labelTrackingArray[b]);
                                        removeChild(spriteArray[b]);
                                        the_world.DestroyBody(blockTrackingArray[b]);
                                        detroyAt.push(b);
                                }
                                var bodyRotation:Number=blockTrackingArray[b].GetAngle();
                                spriteArray[b].rotation = bodyRotation  * (180/Math.PI) % 360;
                                spriteArray[b].x = (blockTrackingArray[b].GetPosition().x * physScale);
                                spriteArray[b].y = (blockTrackingArray[b].GetPosition().y * physScale);
                        }
 
                        for (var d = detroyAt.length-1; d >= 0; --d) {
                                blockTrackingArray.splice(detroyAt[d], 1);
                                labelTrackingArray.splice(detroyAt[d], 1);
                                spriteArray.splice(detroyAt[d], 1);
                                detroyAt.pop();
                        }
 
                }
        }
}

Final Touch

box2d_textfalls.final

Finally, its time to take off the debug view of the physics items and just let the words fall!

package {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFormat;
        import flash.events.Event;
        import flash.utils.Timer;
        import flash.events.TimerEvent;
 
        import Box2D.Dynamics.*;
        import Box2D.Collision.*;
        import Box2D.Collision.Shapes.*;
        import Box2D.Common.Math.*;
 
        public class TextFalls extends Sprite {
                public var the_world:b2World;
                public var physScale:Number=30;
                public var final_body:b2Body;
                public var the_body:b2BodyDef;
                public var the_box:b2PolygonDef;
                public var the_circle:b2CircleDef;
                public var environment:b2AABB = new b2AABB();
                public var gravity:b2Vec2=new b2Vec2(0.0,10.0);
 
                public var dropTextTime:Timer;
                public var blockTrackingArray:Array = new Array();
                public var labelTxt:TextField = new TextField();
                public var labelTrackingArray:Array = new Array();
                public var wordsArray:Array = new Array();
                public var slot=0;
                public var Text:String="Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.";
 
                public var spriteArray:Array = new Array();
                public var holderSprite:Sprite = new Sprite();
 
                public function TextFalls() {
 
                        environment.lowerBound.Set(-100.0, -100.0);
                        environment.upperBound.Set(100.0, 100.0);
                        the_world=new b2World(environment,gravity,true);
 
                        buildWalls();
 
                        addEventListener(Event.ENTER_FRAME, on_enter_frame);
 
                        dropTextTime=new Timer(1000,0);
                        dropTextTime.addEventListener(TimerEvent.TIMER, newText);
                        dropTextTime.start();
 
                        wordsArray=Text.split(" ");
                }
 
                public function buildWalls() {
                        trace("Building Walls");
                        //This Turns on The Ability to View Where the Physics Blockades are (best to get used to the spacing)
                        /*var debug_draw:b2DebugDraw = new b2DebugDraw();
                        var debug_sprite:Sprite = new Sprite();
                        addChild(debug_sprite);
                        debug_draw.m_sprite=debug_sprite;
                        debug_draw.m_drawScale=30;
                        debug_draw.m_fillAlpha=0.5;
                        debug_draw.m_lineThickness=1;
                        debug_draw.m_drawFlags=b2DebugDraw.e_shapeBit;
                        the_world.SetDebugDraw(debug_draw);*/
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 2 / physScale, 768 / physScale);//physScale is used to make calculating time based physics and not frame based.
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(400 / physScale, 20 / physScale);
                        the_box.friction=0.3;
                        the_box.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
 
                        the_body = new b2BodyDef();
                        the_body.position.Set(1024 / 5 / physScale, 768 / 2 / physScale);
                        the_circle = new b2CircleDef();
                        the_circle.radius=3.0;
                        the_circle.density=0;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_circle);
                        final_body.SetMassFromShapes();
 
                }
 
                private function NewTextLabel():void {
 
                        labelTxt = new TextField();
                        labelTxt.autoSize=TextFieldAutoSize.LEFT;
                        labelTxt.cacheAsBitmap=true;
                        labelTxt.embedFonts=true;
 
                        var format:TextFormat = new TextFormat();
                        format.font="Verdana";
                        format.color=0xFFFFFF;
                        if (wordsArray[slot].length==0) {
                                ++slot;
                        }
                        if (slot>=wordsArray.length-1) {
                                slot=0;
                        }
                        labelTxt.text=wordsArray[slot];
                        format.size=20;
                        labelTxt.defaultTextFormat=format;
                        labelTxt.text=wordsArray[slot];
                        ++slot;
                }
 
                public function newText(evt:TimerEvent):void {
                        NewTextLabel();
                        holderSprite = new Sprite();
                        addChild(holderSprite);
                        holderSprite.addChild(labelTxt);
                        labelTxt.x=holderSprite.x-labelTxt.width/2;
                        labelTxt.y=holderSprite.y-labelTxt.height/2;
                        holderSprite.x=-1000;
                        holderSprite.y=-1000;
 
                        spriteArray.push(holderSprite);
                        labelTrackingArray.push(labelTxt);
 
                        var final_body:b2Body;
                        var the_body:b2BodyDef;
                        var the_box:b2PolygonDef;
                        the_body = new b2BodyDef();
                        the_body.position.Set(Math.random()*6.6+10, -1);
                        the_box = new b2PolygonDef();
                        the_box.SetAsBox(labelTxt.width/physScale/2-.1, labelTxt.height/physScale/2-.2);/////////////////Tighten Edges
                        the_box.friction=1;
                        the_box.density=.9;
                        the_box.restitution=.2;
                        final_body=the_world.CreateBody(the_body);
                        final_body.CreateShape(the_box);
                        final_body.SetMassFromShapes();
                        blockTrackingArray.push(final_body);
 
                }
 
                public function on_enter_frame(evt:Event) {
                        the_world.Step(1/30, 10);
 
                        var detroyAt:Array = new Array();
                        var totalBlocks=blockTrackingArray.length;
 
                        for (var b = 0; b < totalBlocks; ++b) {
                                if (blockTrackingArray[b].GetPosition().y>768/physScale) {//Kills Block if it fall past the screen.
                                        spriteArray[b].removeChild(labelTrackingArray[b]);
                                        removeChild(spriteArray[b]);
                                        the_world.DestroyBody(blockTrackingArray[b]);
                                        detroyAt.push(b);
                                }
                                var bodyRotation:Number=blockTrackingArray[b].GetAngle();
                                spriteArray[b].rotation = bodyRotation  * (180/Math.PI) % 360;
                                spriteArray[b].x = (blockTrackingArray[b].GetPosition().x * physScale);
                                spriteArray[b].y = (blockTrackingArray[b].GetPosition().y * physScale);
                        }
 
                        for (var d = detroyAt.length-1; d >= 0; --d) {
                                blockTrackingArray.splice(detroyAt[d], 1);
                                labelTrackingArray.splice(detroyAt[d], 1);
                                spriteArray.splice(detroyAt[d], 1);
                                detroyAt.pop();
                        }
 
                }
        }
}

From here...I'm still not done thinking of possibilities. There is a whole world of things you can do. Where you go, is up to your imagination.

Happy Experimenting
(^_^)//

Tags: , , ,

5 Responses to “Box2DFlash - Falling Text”

  1. bernhard says:

    Hi,
    Thx very much for this awesome tutorial !

    Helped me very much in getting an effect I always wanted on a website.

    Just one question. How could I limit the number of text blocks there are totally. Because if nothing falls below the viewport, its just getting more and more and flash player is getting slower and slower :)

    bernhard

  2. Chris Yanc says:

    Since this is timer based, you could just change the timer settings. dropTextTime=new Timer(1000,0);
    dropTextTime=new Timer(1000, 100); should make it only drop 100 words and then stop.

  3. James Bull says:

    Thanks for the great tutorial, just a quick question. Is there a way to turn the Text:String into hyperlinks?

  4. James Bull says:

    Thanks for the compliments on the site! It looks like I wont be adding the links in, since I am only creating a “demo” for a client before handing the project off to a real flash/as3 developer. But I would like to get a hover effect working. The working demo can be found here:

    http://jamesbull.ca/projects/wax/orda/HelloWorld.html

    But I am getting the following error:

    ArgumentError: Error #1063: Argument count mismatch on MethodInfo-669(). Expected 2, got 1.

    And finally the AS code snippet can be found here:

    http://snipplr.com/view/23307/box2dflash-falling-text/

    I have just started learning AS, and don’t quite understand its syntax, but I’ve been learning and am looking forward to understanding the solution to my dilemma!

Leave a Reply

Downloads

What do you all think?

What developer tool[s] do you use to compile your SWF files?

View Results

Loading ... Loading ...

What kind of tutorial do you prefer?

View Results

Loading ... Loading ...

What is your prefered language for developing multi-touch apps?

View Results

Loading ... Loading ...

Shameless Attempts to Pay the Bills