Author Archive

Speed Tests: Objects vs. Arrays vs. Dictionaries

Tuesday, July 8th, 2008

I’ve been taking buses around Europe for a couple weeks now, and sometimes those trips get extremely long. Yesterday I took a bus from Venice to Seefeld (Austria), a trip that would have taken about five hours if not for the hurricane-like downpour they were having in Italy. Seriously, it was ridiculous- all traffic was on the side of the highway, and all the motorcyclists were huddled under the overpasses. But on the bright side, it did give me a lot of time to try out some things that I normally wouldn’t take the time to do, such as this experiment.

I make a lot of decisions daily based on things I think I know, but really have just always assumed. And so, on this bus ride, I decided to get to the bottom of a few of them. The first experiment I tried was with the read and write speeds of Objects, Arrays, and Dictionaries. In the past, I have always used Arrays when I need all the nifty sorting and organization methods, Dictionaries when I need fast access, object keys, or weak references, and Objects pretty much never (because they’re messy and slow). So yesterday I decided to see if my assumptions were actually valid, or if I had been doing things wrong this whole time.

So I set up a quick class to test. I created a Dictionary, an Object, and an Array, and then I put 100,000 integers in each one for the write test, and read them back out for the read test. This is what I got (all times are average and in milliseconds).

868
Object Array Dictionary
Read (integer key) 19 573
Write (integer key) 24 17 22
Read (string key) 586 N/A 573
Write (string key) 329 N/A 333

Obviously there are many more benchmarks that I could have run, but I also had a pretty good book on that bus. I think I’ve done enough experimentation to prove that, once again, my assumptions are invalid.

Flash + Google = ?

Wednesday, July 2nd, 2008

Sorry for the lack of updates, everyone: I’m currently in Switzerland enjoying the fondue (true story). However, I did stumble across something interesting during my last five-Franc Internet session. Although we’ve all heard for years that Google does index SWFs in some mysterious way, no one has really understood exactly what that meant. All we knew was that it was pretty much useless. However, it looks like Google is getting a little more serious about it, as mentioned in the links below.

Google’s blog:
Google Learns to Crawl Flash

Adobe’s press release:
Adobe Advances Rich Media Search on the Web

However, I still have no idea what this means. After all, any Flash RIA developer worth his salt will be bringing in all his/her data dynamically instead of embedding it in the SWF. I would assume this is the data that Google will be reading, non? Otherwise I’m not sure how it would be different than what we’ve got now. And also because I like to hope for the best, and that would be pretty slick. Game-changing, I’d even say.

So anyway, I’ll leave the in-depth analysis to others. The Alps, after all, are calling.

AS3 Broadcaster Class

Monday, June 23rd, 2008

This is something simple enough that I hesitate to post it, but maybe someone else can benefit. Plus, I always try to have something new on Mondays. Anyway, this a technique I once used back in the dark ages of ActionScript development (meaning AS2). Last week, however, I suddenly had need of it again.

The Scenario

The AS3 event model is a pretty slick deal- much better than the six different ways we used to do it back in AS2. However, I ran into a spot last week in which it failed me. I had several different components in completely different parts of an application, and I wanted them all to listen to each other. That in itself is no problem. The problem was that I also wanted them to be completely unaware of each other, in hopes of keeping the code a bit more encapsulated. So how does one listen for an event that comes from a source whose very existence is unknown?

Option #1

Option #1 was to make all my events bubble, and have each component add event listeners to some display list parent that all the components shared. This would ensure that everyone got their events, but it makes everyone dependent on the current setup. What if I wanted to move a component elsewhere and now it didn’t share that parent? Plus, it’s not a solution that is guaranteed to work in a different app. Plus, it involves children referencing their parent, which I am against on a fundamental, perhaps even a spiritual level. So, scratch Option #1.

Option #2

Then I thought maybe each component should store a reference to all the other components. But once again, you can throw the whole “loosely-coupled” idea out the window. Something about this solution just didn’t feel right.

Option #3

Option #3 was the old AS2 method of creating a central static Broadcaster class and telling everyone to listen to it. Now the only dependency each component had was to one static communication class. Everything else could change as long as they were listening to the Broadcaster. And so, as my great-grandmother has told me, sometimes the old ways are best.

Source

There’s really not much to explain with this class. The only challenge was making a static class into an EventDispatcher, but that turned out to be pretty easy (thanks to G. Skinner, who originally gave me the idea for a static EventDispatcher). Behold:

/**
 * A central event broadcaster
 *
 * @author	Zack Jordan
 * 			{ P I X E L W E L D E R S . C O M }
 */
package com.pixelwelders.events
{
	import flash.events.Event;
	import flash.events.EventDispatcher;

	public class Broadcaster
	{

		private static var eventDispatcher			: EventDispatcher;

		/**
		 * Broadcasts an event to all listeners
		 * To listen to any and all events, use Broadcaster.addEventListener()
		 *
		 * @param	event		The Event to broadcast
		 * @return				nothing
		 */
		public static function broadcast( event:Event ): void
		{
			dispatchEvent( event );
		}

		// === S T A T I C   E V E N T   D I S P A T C H E R ===
		public static function addEventListener( type:String, listener:Function, useCapture:Boolean=false,
			priority:int=0, useWeakReference:Boolean=true ):void
		{
			if ( !eventDispatcher ) eventDispatcher = new EventDispatcher();
			eventDispatcher.addEventListener( type, listener, useCapture, priority, useWeakReference );
		}

		public static function removeEventListener( type:String, listener:Function, useCapture:Boolean=false ):void
		{
			if ( eventDispatcher ) eventDispatcher.removeEventListener( type, listener, useCapture );
  	    	}

		public static function dispatchEvent( p_event:Event ):void
		{
			if ( eventDispatcher ) eventDispatcher.dispatchEvent( p_event );
		}

	}
}

As you can see, this is just a static wrapper for an instance of EventDispatcher. I just route all the methods of the EventDispatcher to static methods, and voilá. As always, if you can think of a better way, just drop it in the comments.

Custom Shapes in FIVe3D: The Arc

Thursday, June 19th, 2008

The beauty of FIVe3D (other than its size, ease of use, and a few other things) is how easily extendable it is. For a previous experiment, I needed a way to draw an arc in 3D space. This isn’t something that FIVe3D provides, and in fact it was a little challenging to find the math I needed. However! Once I found it, I was able to easily use FIVe3D’s drawing API to put it into action.

The arc code, by the way, is from an ancient AS2 function called drawWedge() by Ric Ewing, which drew pizza-style wedges. Close enough. With a little elbow grease I managed to bend it to my will. Here’s an example of a bunch of arcs doing their thing:

And here is the code that draws the arc, which extends FIVe3D’s Drawing class. This could probably be cleaned up a bit, since I run through Ric’s arc code twice to create the thing; it wasn’t originally that way, but getting the fill on the inside of the arc proved more difficult than I originally thought.

/**
 * An extension of Mathieu Badimon's FIVe3D Drawing class.
 * This class draws an additional shape onto a FIVe3D Graphics3D instance.
 * This class includes code from by Ric Ewing.
 * 
 * @author 	Zack Jordan
 * 			{ P I X E L W E L D E R S }
 */
package com.pixelwelders.five3d
{
	import five3D.display.Graphics3D;
	import five3D.utils.Drawing;
 
	public class PXWDrawing extends Drawing
	{
 
		/**
		 * Draws a wedge shape onto a Graphics3D instance.
		 * 
		 * @param 	graphics		a Graphics3D instance on which to draw
		 * @param 	x				x position of the center of this wedge
		 * @param	y				y position of the center of this wedge
		 * @param	startAngle		the angle of one straight line of this wedge
		 * @param	arc				the angle (in degrees) of the total arc of this wedge
		 * @param	xRadius			the external radius along the x axis
		 * @param	yRadius			the external radius along the y axis
		 * @param	innerXRadius	the internal radius along the x axis
		 * @param	innerYRadius	the internal radius along the y axis
		 * @param	color			the color of the wedge fill
		 * @param	fillAlpha		the alpha value of the wedge fill
		 * 
		 * @return					nothing
		 */
		static public function drawWedge( 
			graphics:Graphics3D, 
			x:Number, 
			y:Number, 
			startAngle:Number, 
			arc:Number, 
			xRadius:Number, 
			yRadius:Number, 
			innerXRadius:Number, 
			innerYRadius:Number, 
			color:uint = 0xFF0000, 
			fillAlpha:Number = .5 
		): void
		{
			var segAngle	: Number
			var theta		: Number
			var angle		: Number
			var angleMid	: Number
			var segs		: Number
			var bx		: Number
			var by		: Number
			var cx		: Number
			var cy		: Number;
 
			segs = Math.ceil( Math.abs( arc ) / 45 );
			segAngle = arc / segs;
			theta = -( segAngle / 180 ) * Math.PI;
			angle = -( startAngle / 180 ) * Math.PI;
 
			graphics.lineStyle( 1, 0x000000, 1 );
			graphics.beginFill( color, fillAlpha );
			graphics.moveTo( 
				x + Math.cos( startAngle / 180 * Math.PI ) * innerXRadius,
				y + Math.sin( -startAngle/180 * Math.PI ) * innerYRadius 
			);
 
			// line 1
			graphics.lineTo( 
				x + Math.cos( startAngle / 180 * Math.PI ) * xRadius,
				y + Math.sin( -startAngle / 180 * Math.PI ) * yRadius 
			);
 
			// outer arc
			for ( var i:int = 0; i < segs; i++ ) {
				angle += theta;
				angleMid = angle - ( theta / 2 );
				bx = x + Math.cos( angle ) * xRadius;
				by = y + Math.sin( angle ) * yRadius;
				cx = x + Math.cos( angleMid ) * ( xRadius / Math.cos( theta / 2 ) );
				cy = y + Math.sin( angleMid ) * ( yRadius / Math.cos( theta / 2 ) );
				graphics.curveTo( cx, cy, bx, by );
			}
 
			// line 2
			graphics.lineTo( 
				x + Math.cos( ( startAngle + arc ) / 180 * Math.PI ) * innerXRadius, 
				y + Math.sin( -( startAngle + arc ) / 180 * Math.PI ) * innerYRadius 
			);
 
			theta = -( segAngle / 180 ) * Math.PI;
			angle = -( ( startAngle + arc ) / 180 ) * Math.PI;
 
			// inner arc
			for (var j:int = 0; j < segs; j++ ) {
				angle -= theta;
				angleMid = angle + ( theta / 2 );
				bx = x + Math.cos( angle ) * innerXRadius;
				by = y + Math.sin( angle ) * innerYRadius;
				cx = x + Math.cos( angleMid ) * ( innerXRadius / Math.cos( theta / 2 ) );
				cy = y + Math.sin( angleMid ) * ( innerYRadius / Math.cos( theta / 2 ) );
				graphics.curveTo( cx, cy, bx, by );
			}			
			graphics.endFill();			
		}
	}		
}

Another note on this experiment: the SWF is 16k. Holy crap.

Runtime Libraries in Flex ActionScript Projects

Monday, June 16th, 2008

Runtime library

This is something I’ve begun using recently, and I thought I would post about it to see if I can help anyone else who’s been thinking about this. I’ve seen some other articles on this, but they’ve had some shortcomings that I think I have improved on. Of course, there’s room for tons of improvement on my class as well, so feel free to extend this to your little collective hearts’ content. The source is downloadable at the bottom of the page, or you can continue to the second page of this article to view it all without downloading. Anyway: onward!

The Need

Okay, so: as a Flex developer who does a lot of ActionScript-only projects, I often run into situations in which I need to import some artwork. This artwork may be in any number of formats, and they all require different solutions. However, for a project that I’m working on now (which I would expound upon if it wasn’t [apparently] top-secret), I needed to import hundreds of little images in a vector format. Furthermore, the client hinted that it would be nice, if not mandatory, to be able to swap out images later without sending it back to me for a recompile. So, I had to do a bit of thinking.

However, it turns out that the solution is really not that hard. When working with Flash, there is really only one vector format worth worrying about, and that is SWF. And furthermore, it turns out that there is a kinda slick way to import all the assets contained in a SWF into a Flex ActionScript project. In the following class, I’ve just smoothed the process a little bit.

The Theory

1- Create a MovieClip in Flash CS3 and check Export for ActionScript in its linkage properties. Remember the class name that you give it, because you’re going to need that to pull this asset back out of its mother SWF.

2- Publish your SWF. Make a note of where it’s going so you can load it in Flex.

3- In Flex, set up a Loader with the typical listeners (see my source below for details) and load the SWF.

4- Once the Loader has successfully loaded the SWF, the part you are interested in is the Loader’s contentLoaderInfo property (which is an instance of the LoaderInfo class, if you’d like to check the Flash help files for more information). This property now contains the data from your Flash CS3 SWF. Interestingly enough, a LoaderInfo class contains an instance of the ApplicationDomain class, which in turns contains all class definitions that are contained in that SWF. Since you checked Export for ActionScript on your MovieClip, that means there is a definition for it in the ApplicationDomain of this LoaderInfo. You just need to pull it out and instantiate it.

5- You have to do a little dancing around with types to get your MovieClip back out, since you will be pulling it out as an instance of Class, not as an instance of MovieClip. However, with a couple lines of code, it’s easy enough to actually create an instance of your original Flash CS3-authored MovieClip.

The Code

Here are the vital parts of the code, as seen below in the source download link at the bottom of the page. These are contained in a wrapper class that I wrote that surrounds Loader.contentLoaderInfo.

This is the handler that is called when the Loader successfully loads the SWF. Notice that we save the LoaderInfo (called “contentLoaderInfo”) for later use. This is the package of all the assets we have just imported.

private static function handleLoadComplete( event:Event ): void
{
	loaderInfo = loader.contentLoaderInfo;
	dispatchEvent( new Event( Event.COMPLETE ) );
}

And here is where the real magic happens, and it must be called after the above handler. Notice how we get a real live Sprite instance from the definition in our LoaderInfo instance. Plus, it looks just like the asset you created in Flash at the beginning of this article.

public static function getAsset( id:String ): Sprite
{
	var Asset:Class = loaderInfo.applicationDomain.getDefinition( id ) as Class;			
	return Sprite( new Asset() );
}

Summary

This is as basic as it gets. My source below extends this enough for me to use it in the aforementioned project (as well as adding some basic error handling), but this could be extended for all types of applications. For instance, my class only returns instances of Sprites because that is what I am interested in. However, you could also return the class itself (un-instantiated), or anything that you might find in LoaderInfo.applicationDomain. The possibilities are… well, not limitless. But more than you might think.

Source

The zip contains a RuntimeLibrary class (shown below), an example using it, and some sample assets in a SWF (with the matching FLA so you can see that they are nothing special- just Exported for ActionScript). As you can see, I’m doing some basic error handling, but you may want to do something a little more robust; or, you may want the error. Feel free to change whatever you want- that’s the beauty of open-source!

DOWNLOAD SOURCE

/**
 * A utility to load a SWF at runtime.
 * This makes all definitions in the loaded SWF available.
 * You can use this to load graphics elements created in Flash CS3 into Flex ActionScript projects
 * 
 * @author	Zack Jordan
 * 			{ P I X E L W E L D E R S }
 * 			pixelwelders.com/blog
 */
package com.pixelwelders.graphics
{
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.URLRequest;
 
	public class RuntimeLibrary extends EventDispatcher
	{
 
		private var request				: URLRequest;
		private var loader				: Loader;
		private var loaderInfo			: LoaderInfo;
 
		/**
		 * Constructor- creates a new RuntimeLibrary
		 * 
		 * @param			nothing
		 * @return			The newly-created RuntimeLibrary 
		 */
		public function RuntimeLibrary()
		{
			request = new URLRequest();
			loader = new Loader();
			loader.contentLoaderInfo.addEventListener( Event.INIT, handleLoadComplete );
			loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, handleIOError );
		}
 
		// === A P I ===
		/**
		 * Loads a swf into this RuntimeLibrary
		 * 
		 * @param	url		the URL of the SWF to load
		 * @return			nothing
		 */
		public function load( url:String ): void
		{
			request.url = url;
			loader.load( request );
		}
 
		/**
		 * Creates and returns an instance of the specified class from the loaded SWF
		 * If the specified class does not exist, dispatches an ErrorEvent and returns an empty Sprite
		 * 
		 * @param	id		Name of the class in the loaded SWF
		 * @return			An instance of the specified class, or an empty Sprite if the class is not found
		 */
		public function getAsset( id:String ): Sprite
		{
			try
			{
				var Asset:Class = loaderInfo.applicationDomain.getDefinition( id ) as Class;
			} catch ( error:ReferenceError )
			{
				trace( "Asset not found." );
				dispatchEvent( new ErrorEvent( ErrorEvent.ERROR ) );
			}
 
			return Asset ? Sprite( new Asset() ) : new Sprite();
		}
 
		// === E V E N T   H A N D L E R S ===
		private function handleLoadComplete( event:Event ): void
		{
			loaderInfo = loader.contentLoaderInfo;
			dispatchEvent( new Event( Event.COMPLETE ) );
		}
 
		private function handleIOError( event:IOErrorEvent ): void
		{
			trace( "load error: " + event.text );
		}
 
	}
}

Compiling Astro with Flex 3

Thursday, June 5th, 2008

Flash Player 10

Nothing revolutionary today, folks, on account of the ridiculous amount of time I spent today trying to get Flex 3 to compile Flash 10 SWFs. I had to use a combination of information from several sources, including the below:

Flash 10 / Astro Installation Guides

Adobe’s official page This is probably the place to start.
Ryan Taylor / Boostworthy There are some interesting notes here.
FLEX{er} This is a rather terse (but illustrated!) guide.

It would be pointless for me to go through it again, since I think they’ve pretty much got it covered. However, there are a couple valuable things I learned:

Setup Tips

1- I couldn’t get things to work with the last “stable” build (May 16- v3.0.1.1732), so my advice would be to go with one of the more recent ones. I’m using v3.0.1.1954, myself.

2- There is in fact a debug player, and it is here. I’m not sure why this isn’t mentioned in the documentation.

3- The debug player is standalone, so you won’t be able to debug in your browser. Instead, in your launch configuration (Project > Properties > Run/Debug Settings > New (or Edit)), point the Debug URL to the actual SWF you’re producing, not the generated HTML page. Then you can tell your OS to run SWFs with the standalone debug player, and then you’ll be able to actually see what you’re doing.

4- From my experience, I estimate that actually reading Adobe’s instructions before trying this will save you approximately four and a half hours.

Son of Papervision! (VectorVision vs. FIVe3D)

Saturday, May 31st, 2008

ASIDE: So, the original theme of this article was a head to head between PV3D/VectorVision and FIVe3D, but then I realized that an offspring metaphor was really more apt, as explained below. Nonetheless, the following picture is too awesome not to use.

Papervision vs. FIVe3D

An awesome picture.

If you’ve been following this site for any amount of time, you’ve probably noticed that I’ve been spending quite a bit of time with Mathieu Badimon’s excellent FIVe3D engine. Probably too much time, in fact. I’ve talked about the features in other posts, so I won’t go into it here. If this is the first you’ve heard of it, go take a look at Mathieu’s examples, or click ‘FIVe3D’ in the tag cloud to the right to see what it is and some of the things it’s capable of.

It seems that the first thing people do when they see this engine is compare it with Papervision3D. I’ve resisted this for a long time; in my opinion, bitmap-based and vector-based 3D engines seem to be pretty close to the proverbial apples and oranges. However! As of sometime last week, Papervision and FIVe3D have been combined into some sort of (proverbial?) fruit punch, which means that inter-species comparisons make a lot more sense. It’s called VectorVision, and the men responsible for this unholy union are Barcinski & Jean-Jean, two mad scientists from Amsterdam.

Based on my earlier experiments, I’ve been kicking around the idea of a 3D tag cloud for this blog. FIVe3D, of course, seemed like the obvious man for the job due to its simplicity and the fact that Papervision hasn’t had anything in the way of quality text rendering. However, the experiments of the aforementioned Dutchmen made me wonder how Papervision would handle the task. So, I created a similar application using each library. You can see the results below; each image is a separate SWF- just click one to activate it.

FIVe3D Papervision3D
SWF size: 32k SWF size: 60k

Findings

As you can see, there are some differences; and of course, this is as basic as either engine gets. But in terms of pure capability, it looks like the offspring of PV3D and FIVe3D is indeed greater than either. Post your machine/browser and frame rates; I’d like to see what everyone else is getting.

FIVe3D Cheat Sheet: The Display Classes

Tuesday, May 27th, 2008

As should be obvious, I’ve been pretty fascinated with Mathieu Badimon’s elegant little 3D vector engine FIVe3D for some time now:

Experiments in the Third Dimension: FIVe3D
FIVe3D and TweenLite: Text Cloud
Best FIVe3D Experiment Yet
FIVe3D TextCloud: AS3 Tutorial and Source

And as I’ve mentioned, FIVe3D is in my opinion the easiest Flash 3D engine to pick up and play with. In my tutorial above (link #4), I am able to get a little demo running in just a few lines of ActionScript. However, my tutorial only covers the DynamicText3D class (and to a lesser extent, the Sprite3D class). Thus, as a companion work, I’ve put up a quick summary and comparison of the FIVe3D display classes below. Hopefully this will help tide a few people over until Mathieu releases the real documentation (which will certainly be much more exhaustive than my little effort).

Display Classes

Class Extends Description and Notes Dispatches MouseEvents?
Scene3D Sprite This is the base display class for the FIVe3D display list. It corresponds to the Stage in the normal Flash display list. Put simply, if it ain’t on here, it ain’t getting rendered. Yes
Graphics3D N/A This is the FIVe3D equivalent to the AS3 Graphics class. All FIVe3D display objects (with the exception of Scene3D and Sprite2D) have one, with the instance name of graphics3D. It has many of the same methods as the normal Graphics class, and you can also send an instance to the Drawing class if you want to draw additional shapes. Take a look at the example that comes with FIVe3D to see this in action. N/A
Shape3D Shape This is as basic (and as lightweight) as FIVe3D gets. Sprite3D and Shape3D share the same relationship as Sprite and Shape in AS3: both have a Graphics3D instance for drawing, but Shape3D is non-interactive and cannot have children. No
Sprite3D Sprite Just like a Sprite, but in three dimensions. Unlike Shape3D, this class can have children, each of which adopts its parents’ positions and rotations. It is also interactive. Yes
Sprite2D Sprite Sprite2Ds may be placed in three dimensions (that is, they have x, y, and z coordinates), but they can only rotate around the z axis. In other words, they’re just like normal Sprites with a “z” coordinate. Also, Sprite2Ds do not have a graphics3D object- just the plain old graphics. This means that you can’t use the methods in the Drawing class with this (unless you tweak the Drawing class). Yes
DynamicText3D Sprite3D This is a Sprite3D that displays font glyphs. Think of it as a 3D TextField. You can set the size, color, font (”typography”), and letter spacing. Fonts are kept in the typography package. Yes
Bitmap3D Shape This is analogous to a Shape3D that displays Bitmaps instead of vector graphics. Take a look at the Earth Cube source for an example of this in action.

No
Video3D Bitmap3D Video3D is a dynamic Bitmap3D, and a shell for a Video object. Just like a Video instance, you can use attachNetStream() or attachCamera() to set the video source. No

So let me know if this is useful to you- or if not, what would make it useful (more examples? benchmarks?). Hopefully it will at least give a little clarity to those who are curious about this engine.

Looks Like We Got Ourselves A Protagonist

Friday, May 23rd, 2008

Yes folks, I am still working on OS Wars. And here’s some of the new character art as proof:

Smoking smiley

Fig. A- The heavy weapons… er… smiley.

This was done by Valerie Morrison, a great character designer. We’ve worked on a lot of projects together and I thought she would be perfect to do the characters for the game. And apparently she is, as evinced in Fig. A (above).

FIVe3D TextCloud: AS3 Tutorial and Source

Friday, May 23rd, 2008

A few people have asked me to release the code to my FIVe3D Text Cloud example, so I’ve cleaned things up to the point where I wouldn’t be completely humiliated to release it into the wild. However, I thought I’d touch on a couple points and turn this post into something halfway between a tutorial and an exhibition.

If you just want the source code, you can download it at the bottom of the page. If you’d like the whole shebang, pray read on.

The (new and improved) example:

FIVe3D Basics

FIVe3D is ridiculously easy to set up. In this example, I used the following code to set up everything I needed:

// the Scene3D class is what contains and renders everything else
// think of it as a 3D Stage class
scene = new Scene3D();
scene.x = 375;
scene.y = 200;
addChild( scene );
 
// Sprite3D is, obviously, a 3D version of the standard Sprite class
// it is an actual DisplayObject, so you can use normal positioning, filters, etc. on it
container = new Sprite3D();
scene.addChild( container );

You’ll notice that the syntax is just like AS3 extended into the third dimension. You can nest Sprite3Ds just like Sprites. When you move or rotate the parent Sprite3D, the children will move and rotate with it. The reason I’ve created a container Sprite3D here is so I can rotate several children at the same time.

Now if I wanted to do this the easy way, I could just add my text in one big chunk with the DynamicText3D class that ships with FIVe3D. It works much like the AS3 TextField class, except that the fonts are actually ActionScript files (you’ll see what I mean when you crack open the FIVe3D source).

var txt:DynamicText3D = new DynamicText3D( HelveticaBold ); // HelveticaBold ships with FIVe3D
txt.size = 30;
txt.color = 0xD34328;
txt.text = "Pixelwelders LLC"
container.addChild( txt );

That’s it. The Scene3D class takes care of its own rendering, so you don’t have to trigger it yourself, Papervision-style. Even when a FIVe3D scene looks static, it is actually rendering at your current frame rate. Thus, this is enough code to render 3D text in FIVe3D. Add an ENTER_FRAME listener and increment the container.rotationX property every frame and you’ll see what I mean.

Moving On…

Now this is fine for your everyday run-of-the-mill 3D text, but not for the effect that I had in mind. If I had added my text this way, it would have behaved as a single block, each letter forever doomed to stay wedged firmly between its neighbors. No, I had bigger plans for this text.

For this effect, I created a class called MotifCollection3D. Not a very good name, but typography is not my strong suite and I wasn’t quite sure what else to call it. It’s an extension of the aforementioned FIVe3D Sprite3D class, and it contains one DynamicText3D instance for every letter of the word that it’s currently displaying. This is how you instantiate it:

var cloud:MotifCollection3D = new MotifCollection3D( "PIXELWELDERS LLC", HelveticaBold, 30, 0xD34328 );
container.addChild( cloud );

There’s nothing to it. You send the text, the font class (again, included with FIVe3D), the size, and the color. It creates and assembles all the DynamicText3D instances, and then you can treat it like any other Sprite3D. However, it also includes two methods: assemble(), and the thrillingly-named explode().

Calling either of these methods cycles through all the instances of DynamicText3D and tweens them each to a destination using TweenLite. The explode() method was easy: it just chooses a random destination and rotation for each letter. The assemble() function, on the other hand, was a bit trickier; it needs to know the exact width of every letter in order to place them next to each other.

Happily, that is one of the things that’s included with the FIVe3D typography classes. Each letter, number, and punctuation mark in HelveticaBold contains a __width property, accessible like so:

var letterWidth:Number = HelveticaBold.__widths[ "P" ]; // returns the width of the "P" glyph

That’s a start, but it returns the same width regardless of what size the font is being displayed at. After a little experimentation, I found that this code gives the correct glyph width no matter what size the font:

var letterWidth:Number = HelveticaBold.__widths[ "P" ] * ( size / 100 );

I think that pretty much covers anything novel that I may have done. There are additional comments in the code as well, and it’s only two classes anyway: it shouldn’t be too difficult to figure out anything not explicitly laid out here.

Download Source

Pixelwelders FIVe3D Text Cloud

NOTE: You’ll need to download TweenLite and FIVe3D from their respective sites to get this to run. But you probably already knew that.