One By One Design

Adding Flash/Actionscript Content to a Flex Project

In my recent quest to quick cram as much Flex knowledge possible into my head, I thought I’d take a look at injecting Flash or pure actionscript content into Flex. For those who’ve been using Flex, this will be old hat. For those such as myself, though, who are just making their way into Flex from a Flash development point of view, this may just save a bit of frustration and aggravation.

Probably the easiest way to add a little Flash to a Flex project is to load in a compiled .swf file using the SWFLoader component. Let’s begin with a basic rotating cube made with Actionscript and Papervision3D. I’ll add this to a package named com.onebyonedesign.cube which will later be in the Flex project’s classpath, but for a moment, I’ll just be using good ol’ Flash.

CubeExample.as

package com.onebyonedesign.cube { 

   import flash.display.BitmapData; 
   import flash.display.BitmapDataChannel; 
   import flash.events.MouseEvent; 
   import flash.events.Event; 

   import org.papervision3d.cameras.Camera3D; 
   import org.papervision3d.materials.BitmapMaterial; 
   import org.papervision3d.materials.utils.MaterialsList; 
   import org.papervision3d.objects.primitives.Cube; 
   import org.papervision3d.view.BasicView; 

   public class CubeExample extends BasicView  { 

      private var cube:Cube; 
      private var cam:Camera3D; 

      public function CubeExample(w:Number, h:Number) { 
         super(w, h, false) 
		 addEventListener(Event.ADDED_TO_STAGE, init); 
      } 

      private function init(e:Event):void { 
         createCube(); 
         addEventListener(Event.ENTER_FRAME, entFrame); 
      } 

      private function createCube():void { 
         var bmd:BitmapData = new BitmapData(600, 600, false); 
         bmd.perlinNoise( 600, 600, 3, 5, false, true, BitmapDataChannel.RED); 

         var mat:BitmapMaterial = new BitmapMaterial(bmd); 
         var materialList:MaterialsList = new MaterialsList( { front: mat, right: mat, back: mat, left: mat, top: mat, bottom: mat } ); 
         cube = new Cube(materialList, 600, 600, 600, 2, 2, 2); 

         scene.addChild(cube); 
      } 

      private function entFrame(e:Event):void { 
         cube.rotationY += ((stage.stageWidth / 2) - mouseX) / 150; 
         cube.rotationX += ((stage.stageHeight / 2) - mouseY) / 150; 

         singleRender(); 
      } 
   } 
}

Now, let’s open up Flash and compile a 400×400 pixel .swf containing the CubeExample using the following document class:

package  { 

	import com.onebyonedesign.cube.CubeExample; 
	import flash.display.Sprite; 

	public class CubeTest extends Sprite{ 

		public function CubeTest():void { 
			var ce:CubeExample = new CubeExample(400, 400); 
			addChild(ce); 
		} 
	} 
}

Now, fire up a new Flex project however you normally do so (personally I use the FlashDevelop Actionscript editor and the free Flex SDK). Make sure the .swf you just generated above (we’ll call it “cube.swf”) is in your output directory (usually named “bin”) and create the following Main.mxml file:

<?xml version="1.0"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"> 

	<mx:Panel title="PV3D Cube Example" backgroundColor="#000000"> 

		<mx:VBox width="400" height="400"> 

			<mx:SWFLoader height="400" width="400" source="cube.swf" /> 

		</mx:VBox> 

	</mx:Panel> 

</mx:Application>

Now, after building that file you should wind up with a nice rotating red cube in a black panel.

All good and well, but what if you want to simply use Actionscript to do the work for you rather than precompiling a .swf file in Flash. It’s a little trickier but not much. In order to use the addChild() method of Flex components it’s necessary for your display object to either extend the mx.core.UIComponent object or implement the IUIComponent interface. Since it’s much easier to extend than implement (at least in this case), we’ll go that route. First create a new package com.onebyonedesign.components and add to that package a slightly modified version of our original document class:

package com.onebyonedesign.components { 

	import com.onebyonedesign.cube.CubeExample; 
	import mx.core.UIComponent; 

	public class CubeComponent extends UIComponent { 

		public function CubeComponent():void { 
			var ce:CubeExample = new CubeExample(400, 400); 
			addChild(ce); 
		} 
	} 
}

As you may have noticed, it’s essentially the same as the document class we used to compile our cube in Flash, but now extends the mx.core.UIComponent class rather than the flash.display.Sprite class. And, believe it or not, that is all we need. Now we can add our CubeComponent instance using a teensy bit of actionscript which we’ll call once the application fires its applicationComplete event. Here’s the new .mxml file:

<?xml version="1.0"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()"> 

	<mx:Script> 

		<![CDATA[ 

		import com.onebyonedesign.components.CubeComponent; 

		private function init():void { 
			var cube:CubeComponent = new CubeComponent(); 
			cubeHolder.addChild(cube); 
		} 

		]]> 

	</mx:Script> 

	<mx:Panel title="PV3D Cube Example" backgroundColor="#000000"> 

		<mx:VBox id="cubeHolder" width="400" height="400" /> 

	</mx:Panel> 

</mx:Application>

And, now that our CubeComponent is a bonafide Flex component, we can take this one step further (or at least one step over). If we add a new namespace to our application tag, we can actually add our cubecomponent in .mxml like so:

<?xml version="1.0"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:obo="com.onebyonedesign.components.*" layout="vertical"> 

	<mx:Panel title="PV3D Cube Example" backgroundColor="#000000"> 

		<mx:VBox width="400" height="400"> 

			<obo:CubeComponent/> 

		</mx:VBox> 

	</mx:Panel> 

</mx:Application>

Regardless of which one of the above methods you use – the final product will end up looking something like this.

Posted by