How to integrate 3D Sandy objects into Flex
Posted by Dennis on Sep 27, 2007 in 3D, ActionScript, Flash, Flex • 30 comments
This small demo shows you how you can integrate Sandy objects into a Flex application. Actually, it’s quite simple. All you need to do is create a UIComponent and use the addChild() method with your Sandy Sprite. This demo takes it a tiny bit further and shows you how you can communicate between a 3D object and a Flex component. In order to illustrate this in the most basic way (without too much code clutter), a native Sandy Box object and a simple Flex component (TextInput) are used. When you click on a Sandy Box primitive, a custom event is triggered and handled in the main Flex application MXML. This custom event has a property called “which” and is used to store the name of the Shape3D object that’s been clicked on.
Here are all the code files that make this happen + explanations:
SandyFlex.mxml - The main Flex application File
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="addSandySprite()"
width="400"
height="300"
layout="vertical"
paddingTop="0"
paddingRight="0"
paddingBottom="0"
paddingLeft="0">
<mx:Script>
<![CDATA[
/**
* Add the Sandy object (Boxes) to the UIComponent.
*
*/
private function addSandySprite():void
{
var boxes:Boxes = new Boxes();
boxes.addEventListener( BoxEvent.CLICKED, boxClickedHandler );
spriteContainer.addChild( boxes );
}
/**
* The event handler for the Sandy object's click
* event.
*
* @see BoxEvent
*
*/
private function boxClickedHandler( event:BoxEvent ):void
{
textBox.text = "The " + event.which + " was clicked";
}
]]>
</mx:Script>
<mx:UIComponent id="spriteContainer" width="360" height="200" />
<mx:TextInput id="textBox" />
</mx:Application>
BoxEvent.as - The custom event
package
{
import flash.events.Event;
/**
* BoxEvent.as - Custom event which is dispatched from the Boxes class. In
* this case, it is used to pass the name of the object that's been clicked on.
*
* 26 September 2007
* @author Dennis Ippel - http://www.rozengain.com
*
*/
public class BoxEvent extends Event
{
/**
* The event type
*/
public static const CLICKED:String = "clicked";
/**
* This is used to store the name of the object that's been clicked on.
*/
public var which:String;
/**
* BoxEvent constructor. Nothing special here
* @param type
* @param bubbles
* @param cancelable
*
*/
public function BoxEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
Boxes.as - The Sandy Scene3D with Box primitives
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.GlowFilter;
import sandy.core.Scene3D;
import sandy.core.scenegraph.Camera3D;
import sandy.core.scenegraph.Group;
import sandy.core.scenegraph.Shape3D;
import sandy.materials.Appearance;
import sandy.materials.ColorMaterial;
import sandy.materials.attributes.LightAttributes;
import sandy.materials.attributes.MaterialAttributes;
import sandy.primitive.Box;
/**
* Boxes.as
* 26 September 2007
* @author Dennis Ippel - http://www.rozengain.com
*
*/
[Event( name="clicked", type="sandydemo.BoxEvent" )]
public class Boxes extends Sprite
{
private var scene:Scene3D;
private var selectedMenuItem:Shape3D;
private var box1:Box;
private var box2:Box;
private var box3:Box;
public function Boxes()
{
init();
}
private function init():void
{
// -- configure the camera, move it upwards a little
var camera:Camera3D = new Camera3D( 400, 200 );
camera.y = 25;
camera.z = -150;
camera.lookAt( 0, 0, 0 );
// -- creat the root group and the scene
var root:Group = new Group( "root" );
scene = new Scene3D( "scene", this, camera, root );
// -- box 1
box1 = new Box( "red box", 40, 40, 40 );
configureBox( box1, 0xff0000, -50, -25 );
// -- box 2
box2 = new Box( "yellow box", 40, 40, 40 );
configureBox( box2, 0xffff00, 0, -25 );
// -- box 3
box3 = new Box( "green box", 40, 40, 40 );
configureBox( box3, 0x00ff00, 50, -25 );
scene.render();
}
/**
* The handler for the mouse over event
* @param event
*
*/
private function mouseOverHandler( event:MouseEvent ):void
{
// -- get the target container. The event handler
// was attached to the Shape3D's container. Here
// we use it again to apply a filter
var container:Sprite = event.target as Sprite;
// -- apply a glow filter to the container
container.filters = [
new GlowFilter( 0xffffff, 1, 12, 12 )
];
}
/**
* The handler for the mouse out event
* @param event
*
*/
private function mouseOutHandler( event:MouseEvent ):void
{
// -- get the target container. The event handler
// was attached to the Shape3D's container. Here
// we use it again to remove a filter
var container:Sprite = event.target as Sprite;
container.filters = [];
}
/**
* The handler for the mouse click event
* @param event
*
*/
private function clickHandler( event:MouseEvent ):void
{
// -- get the target container.
var container:Sprite = event.target as Sprite;
// -- get the Shape3D this container is in
var currentShape:Shape3D = getShape3DByContainer( container );
var boxEvent:BoxEvent = new BoxEvent( BoxEvent.CLICKED );
boxEvent.which = currentShape.name;
dispatchEvent( boxEvent );
}
/**
* Compares the given container Sprite to all the container Sprites
* in the scene.
* @param container
* @return
*
*/
private function getShape3DByContainer( container:Sprite ):Shape3D
{
for each( var shape:Object in scene.root.children )
if( shape is Shape3D && shape.container == container )
return shape as Shape3D;
return null;
}
/**
* Adds standard properties to the items
* @param item
* @param color
* @param x
* @param y
*
*/
private function configureBox( item:Shape3D, color:uint, x:int, y:int ):void
{
// -- appearance / material properties
var mattAttr:MaterialAttributes = new MaterialAttributes(
new LightAttributes( false, 0.3 )
);
item.appearance = new Appearance(
new ColorMaterial( color, 100, mattAttr )
);
item.appearance.frontMaterial.lightingEnable = true;
// -- position
item.x = x;
item.y = y;
// -- add event listeners to this Shape3D's container. The
// container is a Sprite, native to Flash
item.container.addEventListener( MouseEvent.MOUSE_OVER, mouseOverHandler );
item.container.addEventListener( MouseEvent.MOUSE_OUT, mouseOutHandler );
item.container.addEventListener( MouseEvent.CLICK, clickHandler );
item.container.useHandCursor = true;
item.container.buttonMode = true;
// -- add this Shape3D to the scene
scene.root.addChild( item );
}
}
}




Nice demo Deniz!
This is really good to know!
Thinking on site UI and business graphics.
Getting an error!
“Type was not found or was not a compile-time constant: Shape3D”
Relates to this line in Boxes.as: private function configureBox( item:Shape3D, color:uint, x:int, y:int ):void
ps. looks cool! by the way. Looking forward to playing around with it.
Hi Declan,
Please check if this line is present in Boxes.as:
import sandy.core.scenegraph.Shape3D;
Yes it is.
I copied the 3 files exactly from above. Boxes.as, BoxEvent.as & SandyFlex.mxml
Great thanks
Wow, looks great nice.
beautifull
Hello.
I have the same error:
1046: Type was not found or was not a compile-time constant: Shape3D.
In Boxes.as line 142
Great post. You make it sound so easy adding integrating 3D objects into flex. I found it to be rather difficult as a novice.
Good work, would really like to learn how to do this.
Nice work. Sound easy but looks difficult
Bunny Vreeland
Hope we will soon get some new posts on this blog
Thanks for the tutorial. It will help me on my school project.
Great tutorial, thanks for it.
Thanks, i have bookmark this this page.
Thanks for the great tips. Love to read your blog, there are so many things to learn here.
Hi all !
Thanks a lot for this tuto! But i’ve got the same error that some of you :
1046: Type was not found or was not a compile-time constant: Shape3D.
I tried a lot of things to fix it but it doesn’t work. If someoone can help me?
(i’m french so forgive my poor english)
For all of the people getting 1046’s. Just Import the whole sandy folder into your Flex project.
Right Click on Project > Import > File System…. Select the expanded root folder of the sandy source…
Voila…
I also import the sandy forlder but it is not working. same error i got it. Can you send me all source file which is no your computer. Realy i need it for my project. Thank you in advance.
well, flex is great ! I love it !
Great, looks really good and sounds really easy – although, it does look difficult with the coding. I like the design though, especially the illumination on each block. If each block could move in, as if it’s a button, it would look really nice. I guess I would have to add all of that in – although, I’m sure it can’t be easy. It’s going to require some major animation. Flex is great, though, really enjoying what can be done with it!
..doesnt work
but still - thanks dude!
here works!
thanks!
This example helped me a lot. Thanks!
For all who get the 1046’s - numeros is right, just copy all Sandy files in your directory where your mxml and as files are.
I am using it “just” with the Flex SDK and copying the Sandy-root dir in my current working dir works well.
PS: If anybody knows how to set the include path for the SDK, pleas let me know.
Good post. I never thought of it that way. Thanks for this entry.
Arrielle Green
Hi its working for me . but how to apply texture to it.
[Embed(source="dog.jpg")]
var Texture:Class;
item.appearance = new Appearance( new ColorMaterial( color, 100, mattAttr ));
i tried to add this code in configureBox function but its not working . Please help me regarding this
Hi its working for me . but how to apply texture to it.
[Embed(source="dog.jpg")]
var Texture:Class;
item.appearance = new Appearance( new BitmapMaterial( new Texture(0,0) ) );
i tried to add this code in configureBox function but its not working . Please help me regarding this
I have the same problem as vijayendra, how could do that?
Nice demo Deniz!
This is really good to know!
but i have mouse over effect. so how to create.
plz tell me