Reflection Utility v1

July 5th, 2007

This utility is great for making quick reflections from MCs or Sprites. You simply pass it the DisplayObject and depending on the method you call, it will return you a reflection copy.

Here are the source files for this class (Reflection Utility). Below is an overview of some of the functions and how to use it. Please feel free to submit bugs or comments below.

Reflection Utility Example

This movie requires Flash Player 9

Click on an example to see it in action

Here I will go through all of the functions and talk about how they are used.

The core of this class is this function:

/**
 * Creates a bitmap copy of any DisplayObject passed in. It can also flip the image vertically for
 * use with making a reflection.
 * @param: original:DisplayObject
 * @param flip: Boolean that defaults to false, use true to have it virtically flip the copy.
 * @return contgainer sprite with copy of orginal image inside.
 **/

internal static function copy_image(original:DisplayObject,flip:Boolean = false):Sprite{
        // Create Container
        var container:Sprite = new Sprite();
        container.name = “copy”;

        // Create BitmapData
        var data:BitmapData = new BitmapData(original.width, original.height, true, 0xFFFFFF);
        data.draw(original);

        // Create Bitmap
        var bmp:Bitmap = new Bitmap(data.clone());

        if(flip){
                bmp.scaleY = -1;
                bmp.y = bmp.height;
        }
        // Add bitmap to container
        container.addChild(bmp);

        // Return container
        return container;

}

This copy_image function does exactly what you expect it to do. You pass it a Display Object (MovieClip, Sprite, Bitmap, and even an externally loaded swf) and it will return a clone of the image back. It also accepts a “flip” boolean that performs a vertical flip on the image. This extra property is what I use to get the reflected image.

Next up are the Mask Methods:

The first Mask method is a simple one:

internal static function create_mask(width:Number, height:Number, color:Number = 0xFF0000):Sprite{

        // Draw mask shape
        var mask:Sprite = new Sprite();
        mask.graphics.beginFill(0xFF0000);
        mask.graphics.drawRect(0, 0, width, height);

        // Return Mask
        return mask;
}

All this does is create a Rectangle mask based on the with and height supplied by the properties. The color is not really needed since a mask is invisible.

The second Mask method creates a more complicated mask called a gradient mask. Gradient masks are key to creating realistic reflections. When you set a Display Object to be masked off by a gradient you get a fading effect like so:

Gradient Mask

This is an image of the gradient mask itself on the left, and the image being masked off on the right


internal static function create_gradient_mask(width:Number,height:Number):Sprite{

        // Create container sprite for gradient
        var container:Sprite = new Sprite();
        container.name = “reflection_mask”;

        // Draw Gradient
        var rect:Shape = new Shape();
        var fillType:String = GradientType.LINEAR;
        var colors:Array = [0xFF0000, 0×000000];
        var alphas:Array = [100, 0];
        var ratios:Array = [0×00, 0xFF];
        var matr:Matrix = new Matrix();
             matr.createGradientBox(width, height/reflection_height, Math.PI / 2, 0, 20);
        var spreadMethod:String = SpreadMethod.PAD;

        rect.graphics.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod)

        rect.graphics.drawRect(0,0,width,height);

        // Add Gradient to container
        container.addChild(rect);

        // Return Container
        return container;
}

As you can see the gradient is created by a Color Matrix and the createGradientBox method. Pay attention to the height property. See how height is divided by the reflection_height variable that is defined at the top of the class. This cuts the gradient down and help make the reflection look smaller and fade off towards the bottom.

The create_reflection takes the above functions and puts into one easy to use package.

internal static function create_reflection(original:DisplayObject):Sprite{
                       
        // Create new container Sprite for reflection
        var reflection:Sprite = new Sprite();
        reflection.name = “reflection_group”;
        reflection.alpha = __reflection_alpha;
                       
        // Make a copy of the DisplayObject and flip vertically
        var image:Sprite = copy_image(original, true);
                       
        // Create Reflection Mask
        var reflect_mask:Sprite = create_gradient_mask(original.width,original.height);
                       
        // Add image and reflectio to the Display List
        reflection.addChild(image);
        reflection.addChild(reflect_mask);
                       
        // Setup Mask
        image.cacheAsBitmap = true;
        reflect_mask.cacheAsBitmap = true;
        image.mask = reflect_mask;
       
        return reflection;
                       
}

This method takes a DisplayObject, copies it, then it creates a GradientMask, and puts it above the copied image. Once everything is in place, we set the image and mask to cacheAsBitmap. This is the key step that allows Flash to display gradient masks. Finally we set the image to be masked off by the gradient, and you wind up with a reflection.

The 3 Reflections method are just simple ways of getting specific types of reflections:

The Reflection Method returns a simple reflection of any DisplayObject you pass into it.

/**
 * Returns a reflection inside of a sprite of the image passed into it.
 * @param: original:DisplayObject
 **/

public static function reflection(original:DisplayObject):Sprite{
        var container:Sprite = create_reflection(original);
        return container;
}

The Simple Reflection method returns the orginal image and its reflection grouped into a new Sprite.

/**
 * Returns original image along with reflection inside of a new Sprite
 * @param: original:DisplayObject
 **/

public static function simple_reflection(original:DisplayObject):Sprite{
        var container:Sprite = new Sprite();
               
        // Create copy of orginal
        var image:Sprite = copy_image(original);
        image.name = “image”;
                       
        // Create reflection
        var reflection:Sprite = reflection(original);
        reflection.y = image.height-1;
        // Add image and reflection into container     
        container.addChild(image);
        container.addChild(reflection);
                                               
        return container;
}

The Advanced Reflection is similar to to the Simple Reflection but it takes the original image and puts it into a new masked off sprite container. This allows separate animation of the image and reflection.

/**
 * This returns an image and reflection organized for animation. The image is placed a mask, and regrouped
 * into a image_group sprite. Also the image’s y is realign to make the image above the 0,0 registration mark
 * and the reflection below the 0,0 mark.
 **/

public static function advanced_reflection(original:DisplayObject):Sprite{
        var container:Sprite = simple_reflection(original);
        // Set up Image Group
        var image_group:Sprite = new Sprite();
        image_group.name = “image_group”;
        // Select Image
        var image = container.getChildByName(“image”);
        var reflection_group = container.getChildByName(“reflection_group”);
        // Create Mask
        var mask:Sprite = create_mask(image.width+50,image.height+100);
        mask.x = -(mask.width/2 - image.width/2);
        mask.y = -(mask.height - image.height);
        mask.alpha = .5;
                       
        // Add image and mask into group
        image_group.addChild(image);
        image_group.addChild(mask);
                       
        // change registration point
        image_group.y = -(image.height);
        reflection_group.y = 0;
        // set mask
        image.mask = mask;
       
        // add image group back into container
        container.addChild(image_group);
                       
        return container;
}

Its also important to note that when using the Advanced Reflection Method, the returned image’s 0,0 (registration mark) is where the image meets the reflection.

Advanced Reflection Registration

The 0,0 registration is located where the Image Meets the Reflection on the Left Hand Side.

When used with the AdvancedReflectionContainer Class you get access to animation methods on the returned image. Here is an example of how to you use it:

import com.jessefreeman.utils.ReflectionUtility;
import com.jessefreeman.views.AdvancedReflectionContainer;

// Create Reflection
var advanced_reflection:Sprite = ReflectionUtility.advanced_reflection(photo_container);

// Place Reflection incside of the AdvancedReflectionContainer
var ar_container:AdvancedReflectionContainer = new AdvancedReflectionContainer(advanced_reflection);

// Offset conatiner because of registration shift
ar_container.x = 250;
ar_container.y = 275;

// Call the open animation on the container
ar_container.open(true);

The Advanced Reflection Container has two methods for opening and closing the animation. Each method accepts a Boolean to trigger wether the action should be animated or instant. When The Container initializes it calls the close method automatically so when you use this class you may not see any graphic on the stage until you call the open method. By extending this class and adding support for call back and events you can create powerful animated reflection with very little code.

Real World Example

Draft Tracker Team Logo Reflections


I used a similar technique on the MLB 2007 Draft Tracker team pull down menu.

2 Responses to “Reflection Utility v1”

  1. The Flash Art of War » Blog Archive » 1 Year Anniversary Says:

    [...] An AS 3 Reflection Utility2 [...]

  2. Venkadesan Tharshan Says:

    thanks

Leave a Reply