So let’s write a little class and try to apply what we have learned so far. The scope of this class will be to create a DisplayObject that will be the reflection of the object passed to it. We will explore wider scopes later on. So all we need to do is to pass an object that we want to apply a reflection to in our constructor:

package ASWC{
import flash.display.*;
public class SimpleReflection extends Sprite{
private var TargetDisplayObject:DisplayObject;
public function SimpleReflection(Target:DisplayObject){
TargetDisplayObject = Target;
}
}//end class
}//end package

In a document class or on the Flash timeline we could create an instance of this class that way:

var reflection:SimpleReflection = new SimpleReflection(test_mc);
addChild(reflection);
reflection.x = test_mc.x;
reflection.y = test_mc.y+test_mc.height+10;

Where test_mc is a MovieClip on the stage with a top left registration.

So the first thing we need in our class is create a copy of the object.

We could try to replicate the graphics property of the object and also to get and replicate all other objects that are currently in the target object display list but that will be slow and overkill. Also if the object is a Flash animation or a movie we would need to somehow synchronize both the object and the reflection.

Instead we will draw directly the object in a BitmapData which is basically like taking a screenshot. So let’s create a new private method that we call from our constructor:

private function CopyAndFlip():void{
var W:Number = TargetDisplayObject.width;//store the width of the target
var H:Number = TargetDisplayObject.height;//store the height of the target
var bmd:BitmapData = new BitmapData(W, H, true, 0x00000000);
//create a bitmapdata with the width and height of the target
bitmap = new Bitmap(bmd);//assign our bitmapdata to a bitmap instance member variable
bmd.draw(TargetDisplayObject);//draw the target in our bitmapdata
addChild(bitmap);//add the bitmap on our instance display list
}

And here we go:


First step done, now we need to flip it. For now just flipping the bitmap will do just fine:

private function CopyAndFlip():void{
var W:Number = TargetDisplayObject.width;
var H:Number = TargetDisplayObject.height;
var bmd:BitmapData = new BitmapData(W, H, true, 0x00000000);
var bitmap:Bitmap = new Bitmap(bmd);
bmd.draw(TargetDisplayObject);
bitmap.scaleY = -1;//flip it vertically
bitmap.y = bitmap.height;//reposition the bitmap
addChild(bitmap);
}


Perfect now let’s create a gradient. We’ll need to import the Matrix class and then we’ll create a new private method:

private function createGradient():void{
var W:Number = TargetDisplayObject.width;
var H:Number = TargetDisplayObject.height;
var myMatrix:Matrix = new Matrix();//create a matrix instance
myMatrix.createGradientBox(W, H, 0, 0, 0);//use this handy method createGradientBox
//and pass it the width and height of the target, leave all other parameter at zero
var colors:Array = [0xFF0000, 0x0000FF];//these are the colors for the gradient
var alphas:Array = [1, 1];//these are the alpha values for the colors
var ratios:Array = [0, 0xFF];//these control how the two colors merge into one another
Mask = new Sprite(); //a new member variable of type Sprite
Mask.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, myMatrix);
//and we set the gradient using our values
Mask.graphics.drawRect(0, 0, W, H);//and we draw it
addChild(Mask);//then we add the gradient to our instance
}

And here it is:


Well the gradient is not in the right direction. Let’s fix that here:

myMatrix.createGradientBox(W, H, 0, 0, 0);

The third value lets us define an angle (in radians) so let’s do just that:

myMatrix.createGradientBox(W, H, Math.PI/2, 0, 0);

And here we go:


Next step is setting the transparency of the colors so we do that here:

var alphas:Array = [1, 0];//change the second value to zero

And here is the result:


Next step is setting the copy and gradient on top of each other but in our case it’s already done. So last step, set both the copy and gradient cacheAsBitmap property to true and then set the gradient as a mask for the copy. Let’s do that in our constructor:

public function SimpleReflection(Target:DisplayObject){
TargetDisplayObject = Target;
CopyAndFlip();//copy and flip our target
createGradient();//create our gradient
bitmap.cacheAsBitmap = true;//set the copy cacheAsBitmap property to true
Mask.cacheAsBitmap = true;//set the gradient cacheAsBitmap property to true
bitmap.mask = Mask;//set the gradient as a mask for the copy
}

And here is our reflection:


Let’s adjust our alpha a bit to get a cleaner result:

var alphas:Array = [0.4, 0];//first value to 0.4

And here our reflection is pretty clean:


Now let’s see how this could work in a real situation. Let’s make it so we can drag the target object and make sure the reflection follows:

test_mc.addEventListener(MouseEvent.MOUSE_DOWN, handleDown);
//register a mouse down event with the object
test_mc.addEventListener(MouseEvent.MOUSE_UP, handleUp);//register a mouse up event with the object
var isDown:Boolean;//create a boolean to check the mouse state
function handleDown(e:MouseEvent):void{
if(e.currentTarget == e.target){//if we mouse down on the target
isDown = true;//then the mouse is down set the boolean to true
e.target.startDrag();//start dragging
addEventListener(MouseEvent.MOUSE_MOVE, handleMove);//and register a mouse move listener
}
}
function handleUp(e:MouseEvent):void{
if(isDown){//the mouse is up, was the mouse down on our object?
isDown = false;//then set the boolean to false
e.target.stopDrag();//stop dragging
removeEventListener(MouseEvent.MOUSE_MOVE, handleMove);//remove the listener
}
}
function handleMove(e:MouseEvent):void{
reflection.x = test_mc.x;//we are moving so set the x property to match the one of the object
reflection.y = test_mc.y+test_mc.height+10;
//set the y property to the object x+height+ a little gap of 10
e.updateAfterEvent();//make sure everything work smoothly
}

And here it is, drag the object around:


Not bad for a simple reflection class but there are still a lot of situations where this class will not work correctly. So let’s study that in the next section.