To create our FlipImageSimple class, we basically transfer the code that you can see in Flipping a Card Effect in Flash CS3, Distorting Bitmaps for Perspective in AS3 from the MainTimeline to a class called FlipImageSimple. ('Simple' as our FlipImage class coming up in the 'Flipping a Card Applet in Terms of ActionScript 3 Custom Classes - Take 2' tutorial will be a bit more complicated.) The process is easy. All we need to do is to follow the class syntax and decide which properties and methods are going to be public and which private.
From our introductory tutorial in 'Bridging the Gap' section we know already the two access modifiers for properties (variables within a class) and methods (functions within a class):
- private - a method or a property designated as 'private' can be accessed only from within the class itself.
- public - a method or a property designated as 'public' can be accessed from anywhere in the program. (Provided the class itself is available. Since we use the generic 'package' keyword, our class can be accessed only by other classes and fla files that reside in the same directory.)
Perhaps we should mention that AS3 provides two other access modifiers:
- protected - a method or a property designated as 'protected' can be accessed from within the class itself and by subclasses of the class.
- internal - a method or a property designated as 'internal' can be accessed by the class itself and classes that reside in the same package.
We will talk more about the latter two modifiers when we discuss packages and extending custom classes in the upcoming tutorials. For now, keeping things as simple as possible, we will use only 'private' and 'public' modifiers.
Making a property or a method 'public' means that a programmer using your class (who potentially does not know or care about the inner workings of your class) will be able to change the value of this property or call the method at will. Thus, each time you declare, say a property, 'public' ask yourself if changing its value can be done from the outside of the class without causing problems in your program. You may ask also if a programmer may conceivably want to change this property's value.
Our FlipImageSimple class is very self-contained and not much is there to customize. The two images and their size can be custom-chosen as the images are passed as parameters to the class constructor. The perspective distortion constant, fLen, is declared as a 'public' property so it can be customized. The only other thing that the user may want to change and cannot in the current version of the class (without editing the class) is the speed with which the images turn. We leave it as a simple excercise to change the class to make the speed customizable.
Hint: The change requires adding a public variable named, say, 'turnSpeed', setting its value to a default value of, say '36', in the constructor, and changing the line within the 'onEnter' function which currently reads:
curTheta+=36;
to
curTheta+=turnSpeed;
If turnSpeed is public, the user can change its value from outside of the class.
Bitmap and BitmapData
Before we present the class's code, let us explain the difference between the Bitmap and the BitmapData classes as we use both. An instance of the Bitmap class is a display object that can be added to the Display List; an instance of the BitmapData class represents all the pixel information of a given bitmap. (Essentially, it is an array corresponding to all the pixels in a given bitmap with their color and alpha information.) If you have a bitmap, say, myBitmap, you access its corresponding BitmapData object and store it in a variable, say myBmpData, as follows:
var myBmpData:BitmapData=myBitmap.bitmapData;
Conversely, if you have an instance of the BitmapData class, say myBmpData, you can obtain the corresponding bitmap object by passing myBmpData to the Bitmap's class contructor. The following code does that and stores the resulting bitmap in a variable myNewBitmap:
var myNewBitmap:Bitmap=new Bitmap(myBmpData);
If you import an image, say myImg to the Library, and link it to AS3 with the default class name myImg, the new class myImg created by Flash that represents your image is a subclass of the BitmapData class. Thus, it is convenient to have our FlipImageSimple class accept the instances of BitmapData as parameters.
The Class Code
Below we explain the code in the class FlipImageSimple. We put our comments as if they were comments within the code to keep the code's flow. We do not repeat the portions of the code that are identical as in the Timeline version in Flipping a Card Effect in Flash CS3, Distorting Bitmaps for Perspective in AS3. For those portions we simply put dotted lines.
package {
//We are importing AS3 built-in classes that our class needs.
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.filters.DropShadowFilter;
/*
Our class extends Sprite (that is, it is a subclass of the Sprite class). Hence, any instance
of the FlipImageSimple class will be a Sprite, with all properties of a Sprite plus additional
properties and methods that we define in our class.
*/
public class FlipImageSimple extends Sprite {
//We are declaring variables. Note that their names are the same as in the Timeline version
//of the applet. The perspective distortion constant, fLen, is public.
public var fLen:Number;
private var bdFirst:BitmapData;
private var bdSecond:BitmapData;
private var picWidth:Number;
private var picHeight:Number;
private var isMoving:Boolean;
private var spSide0:Sprite;
private var spSide1:Sprite;
private var firstSlices:Array;
private var secondSlices:Array;
private var sliceWidth:Number;
private var numSlices:Number;
private var curTheta:Number;
/*
Here comes the class constructor. The constructor takes two parameters of the BitmapData datatype.
These are your images: back and front. The dimensions of both images are assumed to be the same.
We initialize all variables with the same values as in our Timeline script in the Timeline version
of the flipping card. The only difference is positioning of spSide0 and spSide1. We make the change,
so the registration point (the (0,0) point) of each instance of our class will be in the upper left corner.
*/
/*
The word 'this' within a class refers to a particular instance of the class for which
the constructor was evoked. Most of the time using 'this' is optional. For example:
this.fLen=400 and fLen=400 are equivalent.
*/
public function FlipImageSimple(img1:BitmapData,img2:BitmapData){
fLen=400;
isMoving=false;
bdFirst=img1;
bdSecond=img2;
picWidth=img1.width;
picHeight=img1.height;
spSide0=new Sprite();
this.addChild(spSide0);
spSide0.x=picWidth/2;
spSide0.y=picHeight/2;
spSide1=new Sprite();
this.addChild(spSide1);
spSide1.x=picWidth/2;
spSide1.y=picHeight/2;
spSide0.filters = [ new DropShadowFilter() ];
spSide1.filters = [ new DropShadowFilter() ];
firstSlices=[];
secondSlices=[];
sliceWidth=1;
numSlices=picWidth/sliceWidth;
curTheta=0;
cutSlices();
renderView(curTheta);
setUpListeners();
}
/*
Next come the definitions of the functions that create the flipping action. All of those functions are private.
Their names and their content are the same as in the Timeline version of the applet. Within methods, you do not
specify access modifiers to local variables (Of course not, they are accessible only within the method itself.)
Therefore, the content of the functions is literally identical to the content of their Timeline counterparts.
*/
private function cutSlices():void {
//The same as in the Timeline version.
...............
}
private function renderView(t:Number):void {
//The same as in the Timeline version.
...............
}
private function calcMatrixForSides(v0:Array,v1:Array,v2:Array,v3:Array):Matrix {
//The same as in the Timeline version.
...............
}
private function findVecMinusVec(v:Array,w:Array):Array {
//The same as in the Timeline version.
...............
}
/*
The function setUpListeners did not appear in the Timeline version. There we simply put
listeners in the Timeline script as follows:
spSide0.addEventListener(MouseEvent.CLICK,sideClicked);
etc. Within a class ALL CODE MUST BE ENCLOSED in a method or in the constructor
(except for initial variables declarations). Thus, we create a function setUpListeners.
The listeners are identical.
*/
private function setUpListeners():void {
spSide0.addEventListener(MouseEvent.CLICK,sideClicked);
spSide1.addEventListener(MouseEvent.CLICK,sideClicked);
this.addEventListener(Event.ENTER_FRAME,onEnter);
}
private function sideClicked(e:MouseEvent):void {
//The same as in the Timeline version.
...............
}
private function onEnter(e:Event): void {
//The same as in the Timeline version.
...............
}
}
}
With all the functionality placed in an external class, the code on the MainTimeline in card_take1_a.fla is extremely short. We have two images stored in the Library and linked to AS3 with the names 'First' and 'Second'. When we create their instances, we are creating instances of the BitmapData class (more precisely, the instances of its subclasses 'First' and 'Second'). When we create an instance of the BitmapData class, we need to pass the dimensions to the constructor. Hence, we do so. Our images are 166 by 240. Then we create an instance of FlipImageSimple class passing our BitmapData objects to the class constructor as parameters. We store our instance of FlipImageSimple in a variable 'card'. Finally, we position 'card' within the main movie:
var firstImg:BitmapData=new First(166,240);
var secondImg:BitmapData=new Second(166,240);
//The new class, FlipImageSimple, creates a new datatype.
var card:FlipImageSimple=new FlipImageSimple(firstImg,secondImg);
this.addChild(card);
//FlipCardSimple extends the Sprite class. Thus, 'card' is a Sprite and we can
//use methods of the Sprite class to position our card.
card.x=35;
card.y=35;
//fLen=400 is the default value, so you can skip the next line. Unless you want to change
//the distortion for perspective for 400 to a different value.
card.fLen=400;
With all the functionallity encapsulated in a class, the applet is very easy to customize. All you need to do in order to customize the applet is to import your new images, say yourImg1, yourImg2, to the Library and link them to AS3 via the Linkage item in the Library menu. yourImg1 and yourImg2 should be of the same size, say yourWidth, yourHeight, but not necessarily of the same size as our current images, First and Second. Then you change the two lines below:
var firstImg:BitmapData=new First(166,240);
var secondImg:BitmapData=new Second(166,240);
to
var firstImg:BitmapData=new yourImg1(yourWidth,yourHeight);
var secondImg:BitmapData=new yourImg1(yourWidth,yourHeight);
For your fla file to compile, the files FlipImageSimple.as and your fla file must be in the same folder.
Download
- Download all 'fla' and 'as' files corresponding to this tutorial: card_take1.zip
On the next page, we show an applet with two cards flipping. Also, we remove the code from the MainTimeline altogether and place it in another AS3 custom class, CardApp. We use this class as the so-called Document Class for our fla file. The Document Class, new to Flash CS3 and AS3, provides a way of keeping all code in external files and is widely used among AS3 developers.










