Home Labs Galleries PetitOn

Using Sandy 3.0 Flash Library

Part 2. Jump Start

Sandy 3.0 is the version under development with AS3, the latest version of ActionScript. To run AS3 applications you'll need Flash Player 9 and to compile the code, you need Flash 9 public alpha, Flash CS3, Flex SDK or the MTASC compiler. This short introductory tutorial is to show you, how to make a simple world in Sandy 3.0. Note that this version of the library is under heavy development. It is not even in alpha stage and anything can change.

You can download sources for this introduction here.

The basic world

Let us produce a minimal world in Sandy 3.0 with some simple object to show on the stage. As you may know, in AS3 all things are classes and objects - no more sloppy procedural code ;-) Also everything has to reside in a package, which is equivalent to a sub directory where the class file is saved. In the simplest case though, we can use the default package, which means that we don't have to give it a name, and that the class file is saved in the current ( project ) directory.

In our simple world, the only class is the document class. In Flash 9 ( I use the Flash CS3 tool here ) one of the properties of the document is the document class, which we set in the property inspector. We no longer have to write any first frame actions.

Here is the code of SimpleWorld. It is saved in the same directory as the fla file.

package
{
   import flash.display.Sprite; 
   import flash.events.*;
   import sandy.core.World3D;
   import sandy.core.data.*;
   import sandy.core.scenegraph.*;
   import sandy.materials.*;
   import sandy.primitive.*;

   /**
    * SimpleWorld is a demo application to show the minimal Sandy world
    * using the 3.0 version for AS3 of the library.
    * @author petit@petitpub.com
    */
   public class SimpleWorld extends Sprite 
   {
      private var world:World3D;

      public function SimpleWorld()
      {
         // Create an instance of the world
         world = World3D.getInstance();
         // Set the container for the world ( here the Stage )
         world.container = this;
         // Create the scene, the content of the world
         world.root = createScene();
         // Add a camera to the world and set it as child of the root nood
         world.camera = new Camera3D( 200, 200 );
         world.root.addChild( world.camera );
         // Move the camera to see the object
         world.camera.z = -200;
         // Listen to the heart beat and render the world
         addEventListener( Event.ENTER_FRAME, enterFrameHandler );         
      }

      // Create the scene graph based on the root Group of the world
      private function createScene():Group
      {
         // Create the root Group
         var g:Group = new Group();
         // Create a cube so we have something to show
         var cube:Box = new Box( "aCube", 60, 60, 60, "quad" );
         // Create the appearence with a ColorMaterial for the cube
         var appearance:Appearance = new Appearance( new ColorMaterial( 0x0000ff ) );
         cube.appearance = appearance;
         // Add the box to the Group
         g.addChild( cube );
         return g;
      }

      // The Event.ENTER_FRAME event handler tells the world to render
      private function enterFrameHandler( event : Event ) : void
      {
         world.render();
      }
   }
}

Here is the result.

Simple movements

To make the world a bit more interesting, we might like to move things around.
In Sandy 3.0 simple animations are easy to accomplish. Positions and rotations can be applied directly to the camera or any 3D object. Here is a simple example.

package
{
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.*;
    import flash.display.Stage;
    import sandy.core.World3D;
    import sandy.core.data.*;
    import sandy.math.*;
    import sandy.core.scenegraph.*;
    import sandy.materials.*;
    import sandy.materials.attributes.*;   
    import sandy.primitive.*;
    /**
     * SimpleMove is a simple demo on how to rotate a Box
     * in a Sandy 3.0 world. This is AS3!
     * @author petit@petitpub.com
     */
    public class SimpleMove extends Sprite
    {
        private var world:World3D;
        private var box:Box;

        public function SimpleMove()
        {
            stage.frameRate = 40;
            world = World3D.getInstance();
            world.container = this;
            world.root = createScene();
            world.camera = new Camera3D( 200, 200 );
            world.camera.z = -200;
            world.root.addChild( world.camera );
            // The heart beat of the world
            addEventListener( Event.ENTER_FRAME, enterFrameHandler );
        }
        // Create the root Group and the object tree
        private function createScene():Group
        {
            var g:Group = new Group();
            box = new Box( "myBox", 50, 50, 50, "tri", 3 );
	   var lineAttr:LineAttributes = new LineAttributes( 0.5, 0x2111BB, 0.4 )
            var materialAttr:MaterialAttributes = new MaterialAttributes( lineAttr );
            var skin:Appearance = new Appearance( 
			       new ColorMaterial( 0xE0FC9C, 1, materialAttr ) );
            box.appearance = skin;
            box.rotateZ = 45;
            box.rotateY = 30;
            g.addChild( box );
            return g;
        }
        // Render the world and do all once per frame deeds
        private function enterFrameHandler( event : Event ) : void
        {
         box.rotateY += 1;
            world.render();
        }
    }
}

The constructor is the same as before, but we use the new stage property to set the frame rate at 40 fps.

Now let's have a look at the createScene() method!

First we create the Group, which is to become the root Group of the world. Then we create a primitive, again a Box. Setting all sides equal will give us a cube. The constructor takes as arguments our name of the object, the width, height and depth, the creation mode and the quality. The creation mode may can take the value 'tri', to get triangular faces or 'quad' for rectangular faces. Triangular faces gives us better perspective distortion, when we use texture materials, while rectangular faces gives us a bit better performance.

The quality argument determines how many faces a surface is divided into. The higher the quality setting, the better the perspective distortion for textures, and the more resource demanding.

We want the cube to look pretty so we give it an Appearance which contains  a Material. Here we use a ColorMaterial with a yellowish color, an alpha value of 1, i.e we have no transparency. We also pass in a MaterialAttributes object. It can handle line and light attributes. The LineAttributes object is optional, and I include it here to show how the surfaces of the oobject is divided of into triangular polygons.

The LineAttributes is an object in its own right, and is constructed with a thickness, a color and an alpha value. Here the line thickness is 0.5, the color is something bluish and the alpha value is 40%, which is fairly transparent.

The cube is rotated 45 degrees around the z axis and 30 degrees around the x axis, and then added to the root Group.

In the enterFramehandler I have added a small rotational step to take for each frame, which gives a rotation around the y axes. If we want the rotation to be faster we can use bigger increments for the rotation, or we can set a higher frame rate.

If we choose to set a higher frame rate, the motion will be smoother, but the application will demand more resources. You should experiment to get it right.

Here we go.

Interactivity

Often enough we want to offer the visitor to our 3D world the freedom of moving around or change things. So we need a way to capture mouse movements or key presses. Let's say that in the example above, we want to rotate the cube using the arrow keys, and moving the camera forwards and backwards by the Home and End keys.

In AS2 we would just check if one of the keys is pressed by calling the Key.isDown() method.

if ( Key.isDown( Key.KEY_UP ) ) doSomething();

In AS3 this is no longer the case, as all key handling is event driven. We can listen for KeyboardEvent.KEY_DOWN and KeyboardEvent.KEY_UP events, and handle them.

What we want to do here, however, is to check just before we call the world.render() method, if the user holds down a special key, and move an object or the camera acordingly.

To make this possible, we could build the logic into the application, or we could write a utility class that mimics the Key class from AS2. As so many times before, senocular has already done the work for us, and you can find it here with description.

Here is the local copy of the Key class in the default package ready to put in our project directory.
Before we can use the Key class, we have to initialize it by calling its initialize( stage ) method, passing a reference to the Stage object. When in focus, the Stage object catches key presses, via the Keyboard object.

We initialize the Key class i our FirstCube constructor.

Key.initialize( stage );

Then we change the enterFrameHandler to use the Key class, and move things around.

   private function enterFrameHandler( event : Event ) : void
   {
      if (Key.isDown(Keyboard.LEFT)) {
         box.rotateY += 1;
      }
      if (Key.isDown(Keyboard.RIGHT)) {
         box.rotateY -= 1;
      }
      if (Key.isDown(Keyboard.UP)) {
         box.rotateX += 1;
      }
      if (Key.isDown(Keyboard.DOWN)) {
         box.rotateX -= 1;
      }
      if (Key.isDown(Keyboard.PAGE_UP)) {
         world.camera.moveForward(1);
      }
      if (Key.isDown(Keyboard.PAGE_DOWN)) {
         world.camera.moveForward(-1)
      }
      world.render();
   }

The first four if statements use the arrow keys to rotate the cube around the x and y axes. The two last statements use the PageUp and PageDown keyboard keys to move the camera forwards or backwards.

You can test it here ( click to get focus ).

What now?

Of course you want to do a lot of experimenting yourself.
If you want to try out my more detailed tutorial, just follow the developing tutorial series.

We'll start by examining the Sandy Primitives.

TODO:

( This is a reminder for the author )
This will be part of the longer tutorial

Other primitives

Different materials - selectable by radio button

Front side and back side - a plane - inside a box

Rotating object by mouse

And a lot more.

Stay tuned!