Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Creative tools for business
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / Flash Developer Center /

Creating movie clips with reflections in ActionScript 3.0

by Ben Pritchard

Ben Pritchard
  • pixelfumes.com

Modified

23 July 2007

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
ActionScript Flash Professional graphic effects

Requirements

Prerequisite knowledge

This article is intended for Flash developers who have an intermediate to advanced understanding of ActionScript 2.0 or 3.0 and also of ActionScript classes.

User level

Intermediate

Required products

  • Flash Professional (Download trial)
  • Flash Player

Sample files

  • reflect_class_as3.zip (4 KB)

You're probably aware of those nice reflections appearing in some of the latest websites, online ads, and even software. It's an effect common to "Web 2.0" designs, in which something like an album cover or video player appears to reflect some sort of virtual floor beneath it. This tutorial steps you through the creation of the Reflect class, a custom ActionScript 3.0 class that you can apply to reflections on movie clips (and use to modify them) in your Flash CS3 Professional projects.

The Reflect class is intended for any developer or designer who would like to achieve an effect that gives a great impact to your design, but with little effort. Typically it would take a fair amount of effort to manually create reflections in your Flash files. This task would likely involve copying and pasting a clip and then modifying it to achieve the look of the reflection. Every time a change was made, you would need to update your effect. If you had an animated clip or video that you wanted to reflect, it might become completely unfeasible or even impossible. However, the Reflect class allows you to apply the reflection only once because it dynamically updates itself as a true mirror of the clip which it is reflecting.

My work on this ActionScript 3.0 class is a testament to my own love of the Flash community, which is unlike any other pool of developers or designers I know. If you ever need any help with code or features, they are willing to help. After my original code for reflecting movie clips in ActionScript 2.0 was released on my blog, many gracious members of the Flash community posted helpful comments, feature requests, and even code snippets to help improve the class. The updated class described in this article takes into consideration these additions from users who dedicated their time and effort to help me improve it.

Getting started with reflections

Before we get started, it might be useful to demonstrate the effect I am describing. As you drag the sliders in the Reflection Explorer (see Figure 1), you will notice that the Reflection Code box dynamically updates and provides you with the code necessary for applying the reflection to the Flash file. This example, which requires Adobe Flash Player 9 (version 9,0,45,0 or later), assumes a movie clip with an instance name of ref_mc.

This content requires Flash To view this content, JavaScript must be enabled, and you need the latest version of the Adobe Flash Player. To view this content, JavaScript must be enabled, and you need the latest version of the Adobe Flash Player.

Figure 1. Reflection Explorer (drag the sliders to see the effect)

Click the Show Video button at the top of the Reflection Explorer to toggle between a video and its image-based reflection. You may notice that when you are applying the Reflect class to the image, you are setting an update time of –1. This saves on processor overhead because you don't need to constantly update the reflection, as you would with the video. I will cover all of these parameters later in this article.

Examining the Reflect class

Whenever you start a class file, you should set the package library. The following line defines the package library path for the Reflect class:

package com.pixelfumes.reflect

For practical purposes, I named this file Reflect.as and nested it within a specific folder structure. This helps ensure that my code does not conflict with any other existing Reflect class code library that exists. For my purposes, I nested the class in the package path of com.pixelfumes.reflect. You really could make this whatever you want, but remember that the Reflect.as file needs to be in a folder structure that follows the package library. As you can see in the code download, the \com folder contains a \pixelfumes folder, which contains a \reflect folder in which the Reflect.as file lives.

Importing other classes

The Reflect class takes advantage of a number of classes. As you follow through the code, you will see objects from these classes in use. First import the classes in order to make use of them within the Reflect class:

package com.pixelfumes.reflect{ import flash.display.MovieClip; import flash.display.DisplayObject; import flash.display.BitmapData; import flash.display.Bitmap; import flash.geom.Matrix; import flash.display.GradientType; import flash.display.SpreadMethod; import flash.utils.setInterval; import flash.utils.clearInterval;

Writing the Reflect class

Now that you have the imported classes set, you can start writing the actual Reflect class. In this case, you are extending the MovieClip class. The following code opens the Reflect class and sets several variables that are used for tracking the information pertinent to the Reflect class:

public class Reflect extends MovieClip{ //Created By Ben Pritchard of Pixelfumes 2007 //Thanks to Mim, Jasper, Jason Merrill and all the others who //have contributed to the improvement of this class //static var for the version of this class private static var VERSION:String = "4.0"; //reference to the movie clip we are reflecting private var mc:MovieClip; //the BitmapData object that will hold a visual copy of the mc private var mcBMP:BitmapData; //the BitmapData object that will hold the reflected image private var reflectionBMP:Bitmap; //the clip that will act as out gradient mask private var gradientMask_mc:MovieClip; //how often the reflection should update (if it is video or animated) private var updateInt:Number; //the size the reflection is allowed to reflect within private var bounds:Object; //the distance the reflection is vertically from the mc private var distance:Number = 0;

Once you have the global variables for the class's scope defined, you can write the constructor function. The constructor function of the Reflect class accepts an object, which is referred to as args in the example below. The args object is responsible for passing the user-defined data into the Reflect class. For example, a typical instantiation of the Reflect class would look something like this within the Flash document:

import com.pixelfumes.reflect.*; var r1:Reflect = new Reflect({mc:ref_mc, alpha:50, ratio:50, distance:0, updateTime:0, reflectionDropoff:1});

Notice that to use the class, you have to import the Reflect class using the package's code library path already defined—namely, com.pixelfumes.reflect. After importing the class for use, define a variable to hold a reference to the Reflect class instance and pass it several items wrapped in an object. In this case, pass in the movie clip being reflected, the alpha for the reflection, the ratio to use in the gradient mask, the distance of the reflection, the update time, and the reflection dropoff.

The arguments are then pulled from the args object and used to set the class variables defined earlier. Based on the data passed into the class, you can set some additional variables within the class, such as the clip's height and width and the bounds in which the reflection can appear:

function Reflect(args:Object){ /*the args object passes in the following variables /we set the values of our internal vars to math the args*/ //the clip being reflected mc = args.mc; //the alpha level of the reflection clip var alpha:Number = args.alpha/100; //the ratio opaque color used in the gradient mask var ratio:Number = args.ratio; //update time interval var updateTime:Number = args.updateTime; //the distance at which the reflection visually drops off var reflectionDropoff:Number = args.reflectionDropoff; //the distance the reflection starts from the bottom of the mc var distance:Number = args.distance; //store width and height of the clip var mcHeight = mc.height; var mcWidth = mc.width; //store the bounds of the reflection bounds = new Object(); bounds.width = mcWidth; bounds.height = mcHeight;

Now that you have that out of the way, you can start getting into the meat of the class. The Reflection class makes heavy use of the BitmapData class, which enables you to take visual snapshots of movie clips with its draw method. Using the draw method, you can snapshot the movie clip passed into the class and use the data to populate a Bitmap object. Once you have the Bitmap object created, you can flip it upside down, position it, and add it to the Display Object stack. The following code handles the creation of the BitmapData and Bitmap objects, as well as handles their positioning:

//create the BitmapData that will hold a snapshot of the movie clip mcBMP = new BitmapData(bounds.width, bounds.height, true, 0xFFFFFF); mcBMP.draw(mc); //create the BitmapData the will hold the reflection reflectionBMP = new Bitmap(mcBMP); //flip the reflection upside down reflectionBMP.scaleY = -1; //move the reflection to the bottom of the movie clip reflectionBMP.y = (bounds.height*2) + distance; //add the reflection to the movie clip's Display Stack var reflectionBMPRef:DisplayObject = mc.addChild(reflectionBMP); reflectionBMPRef.name = "reflectionBMP";

If you were to finish the class here by closing up the constructor and package, you would be presented with a movie clip that looks like Figure 2.

Image after creating the BitmapData and Bitmap objects
Figure 2. Image after creating the BitmapData and Bitmap objects

As you can see, the class is copying the visual representation of the movie clip, flipping it upside down and positioning itself under the original movie clip.

Creating the gradient

Now that you have the reflected image in the proper position, you can create a movie clip that holds the gradient that you'll use to create the gradient mask:

//add a blank movie clip to hold our gradient mask var gradientMaskRef:DisplayObject = mc.addChild(new MovieClip()); gradientMaskRef.name = "gradientMask_mc"; //get a reference to the movie clip - cast the DisplayObject that is returned as a MovieClip gradientMask_mc = mc.getChildByName("gradientMask_mc") as MovieClip;

With the gradient mask clip added to the display, you can now work on the actual gradient. This gradient uses several values of interest. To create the gradient, you can use the alpha and ratio variables that were passed. These variables, along with the bounds I defined earlier, construct a gradient box within the gradientMask_mc clip.

The following code steps you through the creation of the linear gradient you will be using. Feel free to experiment with different fillType and spreadMethod instances, as these will alter the final appearance of your gradient mask:

//set the values for the gradient fill var fillType:String = GradientType.LINEAR; var colors:Array = [0xFFFFFF, 0xFFFFFF]; var alphas:Array = [alpha, 0]; var ratios:Array = [0, ratio]; var spreadMethod:String = SpreadMethod.PAD; //create the Matrix and create the gradient box var matr:Matrix = new Matrix(); //set the height of the Matrix used for the gradient mask var matrixHeight:Number; if (reflectionDropoff<=0) { matrixHeight = bounds.height; } else { matrixHeight = bounds.height/reflectionDropoff; } matr.createGradientBox(bounds.width, matrixHeight, (90/180)*Math.PI, 0, 0);

With the variables for the gradient mask now populated, you can now use the graphics property of the gradientMask_mc clip to create the GradientFill fill. Once the fill is created within the clip, position gradientMask_mc over reflectionBMP:

//create the gradient fill gradientMask_mc.graphics.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod); gradientMask_mc.graphics.drawRect(0,0,bounds.width,bounds.height); //position the mask over the reflection clip gradientMask_mc.y = mc.getChildByName("reflectionBMP").y - mc.getChildByName("reflectionBMP").height;

For the reflection to be properly masked with the gradient mask, you need to ensure that both the gradient mask and the reflectionBMP are set to cacheAsBitmap = true:

//cache clip as a bitmap so that the gradient mask will function gradientMask_mc.cacheAsBitmap = true; mc.getChildByName("reflectionBMP").cacheAsBitmap = true; //set the mask for the reflection as the gradient mask mc.getChildByName("reflectionBMP").mask = gradientMask_mc;
//cache clip as a bitmap so that the gradient mask will function gradientMask_mc.cacheAsBitmap = true; mc.getChildByName("reflectionBMP").cacheAsBitmap = true; //set the mask for the reflection as the gradient mask mc.getChildByName("reflectionBMP").mask = gradientMask_mc;

Checking your constraints

For the final part of the constructor, check to see if you have a valid update time, which refreshes the BitmapData that contains a snapshot of the movie clip you are reflecting. Clips that don't move and are not animated do not need an update time. If you pass in –1, you can avoid creating an interval to update the BitmapData object and save processing overhead. Movie clips containing videos or buttons that change upon rollover should have an update applied to them, so that the reflection remains visually accurate:

//if we are updating the reflection for a video or animation do so here if(updateTime > -1){ updateInt = setInterval(update, updateTime, mc); }

Adjusting the reflection with methods

With the bulk of the class out of the way, all you need now are a few methods to adjust the reflection. The setBounds method allows you to define an area in which the reflection is available. Keep in mind that, because you are taking a snapshot of the area defined by this method; larger bounds will use more memory. The setBounds method is ideal for clips that animate along a horizontal access within their own timeline.

Take a look at the animation in Figure 3 (click Start Demo to see the effect, Stop Demo to pause it). If a clip has the Reflect class applied to it at runtime, and then the clip's timeline moves items outside of the initial bounds of the clip, the Reflect class will not show them because it had its bounds defined by the size of the clip at runtime.

This content requires Flash To view this content, JavaScript must be enabled, and you need the latest version of the Adobe Flash Player. To view this content, JavaScript must be enabled, and you need the latest version of the Adobe Flash Player.

Figure 3. Animation using setBounds (click Start Demo to see the effect)

Using setBounds enables the user to compensate for the size difference by increasing the size of the bounds if needed:

public function setBounds(w:Number,h:Number):void{ //allows the user to set the area that the reflection is allowed //this is useful for clips that move within themselves bounds.width = w; bounds.height = h; gradientMask_mc.width = bounds.width; redrawBMP(mc); }

The redrawBMP method, used by the setBounds class, serves the role of destroying the current BitmapData and creating a new one to compensate for the new bounds that were defined:

public function redrawBMP(mc:MovieClip):void { // redraws the bitmap reflection - Mim Gamiet [2006] mcBMP.dispose(); mcBMP = new BitmapData(bounds.width, bounds.height, true, 0xFFFFFF); mcBMP.draw(mc); }

The update method refreshes the data held within the BitmapData snapshot of the movie clip. The more often the update method is run, the more processer-intensive the class becomes but the smoother the reflection playback looks. A good rule of thumb is to use as high a number as the visual performance will allow when setting the update time:

private function update(mc):void { //updates the reflection to visually match the movie clip mcBMP = new BitmapData(bounds.width, bounds.height, true, 0xFFFFFF); mcBMP.draw(mc); reflectionBMP.bitmapData = mcBMP; }

Terminating the reflection

You need a way to get rid of that reflection once you have created it. For this, you can create the destroy method, which removes the reflection items from the DisplayObject stack, clears the intervals, and removes all traces of the reflection:

public function destroy():void{ //provides a method to remove the reflection mc.removeChild(mc.getChildByName("reflectionBMP")); reflectionBMP = null; mcBMP.dispose(); clearInterval(updateInt); mc.removeChild(mc.getChildByName("gradientMask_mc")); }

Where to go from here

The Reflect class still has quite a few possibilities, and it leaves plenty of room for extension and improvement. Although using the Reflect class is pretty straightforward when working with static images, it becomes a bit different when reflecting items such as video. If you plan on reflecting a clip containing video, it is best to wait until the video is completely loaded before applying the class.

I would love to see any improvements and additions you would like to add to the Reflect class. Contact me at my blog, pixelfumes.com/blog. The more that we in the Flash community can push one another, the further we will push the boundaries of Flash as a platform.

More Like This

  • Controlling the appearance of text elements with the Text Layout Framework
  • Optimizing content for Apple iOS devices
  • Creating ActionScript 3.0 components in Flash – Part 6: Invalidation model
  • Creating ActionScript 3.0 components in Flash – Part 7: Focus management
  • Creating ActionScript 3.0 components in Flash – Part 8: Keyboard support
  • Using timeline labels to dispatch events with the ActionScript 3.0 TimelineWatcher class
  • Introducing the ActionScript 3.0 debugger
  • Multitouch and gesture support on the Flash Platform
  • Augmented reality with animated avatars using the 3D drawing API
  • Flash glossary: Preloader

Flash User Forum

More
04/23/2012 Auto-Save and Auto-Recovery
04/23/2012 Open hyperlinks in new window/tab/pop-up ?
04/21/2012 PNG transparencies glitched
04/01/2010 Workaround for JSFL shape selection bug?

Flash Cookbooks

More
02/13/2012 Randomize an array
02/11/2012 How to create a Facebook fan page with Flash
02/08/2012 Digital Clock
01/18/2012 Recording webcam video & audio in a flv file on local drive

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement