3D Boxes via ActionScript 3 – Part 2

February 6, 2009 by: smonte

This is the second part of the “Flash 3D Boxes via ActionScript 3″ tutorial. In this part, I will take the 3D animation one step further. In this tutorial, we’ll create a sine wave of boxes and learn how to animate them.

I am assuming that you have already completed the “Flash 3D Boxes via ActionScript 3″. Therefore, I will mainly concentrate on ActionScript in this tutorial.

Setting up the environment

1. First, create three sliders on the top left corner. Give them instance names that are seen in the picture below.

Sliders

Moving into ActionScript 3

2. In the first frame of your main timeline, type the following code.

//First let's configure the sliders.
angleSpeedSlider.value = 10;
angleSpeedSlider.minimum = 1;
angleSpeedSlider.maximum = 30;
 
zSpeedSlider.value = 7;
zSpeedSlider.minimum = 1;
zSpeedSlider.maximum = 20;
 
radiusSlider.value = 7;
radiusSlider.minimum = 1;
radiusSlider.maximum = 20;
 
//The maximum depth
const MAXIMUM_Z:Number = 450;
 
//The number of the boxes
const NUMBER_OF_BOXES:Number = 14;
 
//Create an array that will contain all the boxes
var boxes:Array = new Array();
 
//Set the focal length
var focalLength:Number = 300;
 
//Set the vanishing point
var vanishingPointX:Number = stage.stageWidth / 2;
var vanishingPointY:Number = 20;
 
//The 3D floor for the boxes
var floor:Number = 80;
 
//The starting depth
var startingDepth:Number = MAXIMUM_Z;
 
//The z distance between two boxes
var zDistance:Number = 50;
 
//The depth speed (how fast the boxes are moving towards you)
var zSpeed:Number = -(zSpeedSlider.value);
 
//We assign a different starting angle for each box (we increment this later on)
var angle:Number = 0;
 
//Angle difference between the boxes
var angleDifference:Number = 0.3;
 
//How fast the angle changes
var angleSpeed:Number = angleSpeedSlider.value * 0.01;
 
//The radius for the boxes
var radius:Number = radiusSlider.value * 10;
 
//This loop creates and positions the boxes (starting from the box furthest away)
for (var i=0; i < NUMBER_OF_BOXES; i++) {
 
        //Create a new box
        var box:MyBox = new MyBox();
 
        //Calculate the 3D x position (we will do a sine wave)
        box.xpos3D = Math.sin(angle) * radius;
 
        //Save the angle information for the box
        box.currentAngle = angle;
 
        //Increase the starting angle for the next box
        angle += angleDifference;
 
        //3D y position is the same for all the boxes 
        box.ypos3D=floor;
 
        //Assign a z value for the box (the greater the z, the further away the box is)
        box.zpos3D=startingDepth;
 
        //Update the starting depth for the next box
        startingDepth-=zDistance;
 
        //Calculate the scale ratio for the box
        var scaleRatio = focalLength/(focalLength + box.zpos3D);
 
        //Scale the box according to the scale ratio
        box.scaleX=box.scaleY=scaleRatio;
 
        //Position the box on to the stage (from 3D to 2D coordinates)
        box.x=vanishingPointX+box.xpos3D*scaleRatio;
        box.y=vanishingPointY+box.ypos3D*scaleRatio;
 
        //Push the box to the array
        boxes.push(box);
 
        //Add the box on to the stage
        addChild(box);
}
 
//We use ENTER_FRAME for the animation
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
 
//This function is called in each frame
function enterFrameHandler(e:Event):void {
 
        //First, let's get the dynamic speeds from our sliders
        angleSpeed=angleSpeedSlider.value*0.01;
        zSpeed = -(zSpeedSlider.value);
        radius = radiusSlider.value * 10;
 
        //Loop through the array of boxes
        for (var i=0; i < NUMBER_OF_BOXES; i++) {
 
                //Save the box to a local variable
                var box:MyBox = (MyBox)(boxes[i]);
 
                //Update the z position of the box
                box.zpos3D+=zSpeed;
 
                //Update the current angle of the box
                box.currentAngle+=angleSpeed;
 
                //If zpos3D <= -focalLength, we end up with a negative scaleRatio (or we are dividing by zero).
                //At this point, we know that the object has already passed "us".
                //Therefore, we put the box behind the last box of the line.
                if (box.zpos3D<=- focalLength) {
 
                        //Save the last box to a local variable
                        //The last box of the line is always first in the array,
                        //because of the sortZ() function.
                        var lastBox:MyBox = (MyBox)(boxes[0]);
 
                        //Position the box behind the last box
                        box.zpos3D=lastBox.zpos3D+zDistance;
 
                        //Get the new angle for the box (same as the last box's, minus the angle difference).
                        //This way the box wave stays uniform.
                        box.currentAngle=lastBox.currentAngle-angleDifference;
                }
 
                //Calculate the new 3D x position
                box.xpos3D=Math.sin(box.currentAngle)*radius;
 
                //Calculate a scale ratio for the box
                var scaleRatio = focalLength/(focalLength + box.zpos3D);
 
                //Scale the box according to the scale ratio
                box.scaleX=box.scaleY=scaleRatio;
 
                //Set an alpha according to the scale ratio
                box.alpha=scaleRatio-0.5;
 
                //Position the box on to the stage (from 3D to 2D coordinates)
                box.x=vanishingPointX+box.xpos3D*scaleRatio;
                box.y=vanishingPointY+box.ypos3D*scaleRatio;
        }
 
        //Sort the boxes according to depth
        sortZ();
}
 
//This function sorts the boxes so they overlap correctly
function sortZ():void {
 
        //Sort the array so that the box which has the highest 
        //z position (= furthest away) is first in the array
        boxes.sortOn("zpos3D", Array.NUMERIC | Array.DESCENDING);
 
        //Set new child indexes for the boxes
        for (var i:uint = 0; i < NUMBER_OF_BOXES; i++) {
                setChildIndex(boxes[i], i);
        }
}

You are done, test your movie :)The code should be commented well enough, so I will not go over that. As you can see, 3D animation is not that much harder than 2D. We just position the objects to an imaginery 3D environment and then convert the 3D coordinates in to 2D coordinates. If have any questions, please post them in the forum.

  • Digg
  • Sphinn
  • del.icio.us
  • Mixx

Related tutorials:

  1. 3D Boxes via ActionScript 3 – Part 1
  2. 3D Tunnel with ActionScript 3
  3. Vertical 3D Carousel with ActionScript 3
  4. 3D Tunnel Around Text
  5. Multiple 3D Carousels with ActionScript 3



Filed under: ActionScript 3 Advanced
Tags:

Comments

4 Responses to “3D Boxes via ActionScript 3 – Part 2”
  1. Monty says:

    Any chance of the same tutorial with the new flash 10 z property.

    Log in to Reply
  2. smonte says:

    Thanks, I updated the code!

    Log in to Reply
  3. David says:

    Very nice set of tutorials – I appreciate the math. Just one quick thing – the second tutorial won’t quite compile, because the MyBox.as class from the first tutorial is missing a variable which the second tutorial needs (the currentAngle attribute). Easily fixed with the addition of

    public var currentAngle:Number = 0;

    to the MyBox class and all is well.

    Thanks again!

    Log in to Reply

Leave a Reply

You must be logged in to post a comment.