The SymbolCanvas class

The SymbolCanvas class

The SymbolCanvas class primarily utilizes the private access keyword rather than protected, since SymbolCanvas is less likely to be extended. Because other classes utilize SymbolCanvas via composition rather than subclass- ing, it will therefore be safer to add new methods to SymbolCanvas as you progress, as long as the old methods continue to function as expected. When you want to make

a method or property available to another class, you will use the public keyword.

1. Create a new class named SymbolCanvas. Save the file as SymbolCanvas.as in the examples/com/anim/fx

folder.

2. Update the first line in the script to reflect the proper package: package com.anim.fx {

Chapter 3 Introduction to ActionScript Classes

3. Let’s first add the three methods that were established from writing the MotionBrush class. Add the following

code just below the constructor block: public function update():void{

public function dispose():void{

public function getBitmap():Bitmap {

4. Add the following properties above the constructor method:

private var offset:Point; private var bmd:BitmapData; private var bmp:Bitmap; private var src:DisplayObject; private var clearOnUpdate:Boolean; private var hideOriginal:Boolean;

The first property, offset , will ensure that your effect always renders in the proper place on Stage (no matter how many symbols are nested above your symbol). The next two properties store the BitmapData and Bitmap objects that you’ll use to render any and all effects. The last three properties store the information that you

passed from the new SymbolCanvas instantiation in the

MotionBrush class.

5. Update the constructor method to match the high- lighted code that follows:

public function SymbolCanvas( symbol:DisplayObject, ➥ hideOriginalSymbol:Boolean=false, ➥ clearCanvasOnUpdate:Boolean=true ){

initSymbolCanvas(symbol, hideOriginalSymbol, ➥ clearCanvasOnUpdate); }

Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques

This code informs the constructor function of how many and what types of arguments to accept. These parameters must match the arguments used in the MotionBrush class. The symbol parameter

is typed to DisplayObject for forward compatibil- ity. The DisplayObject class is a distant superclass of the MovieClip class. As a refresher, here is the inheritance chain for MovieClip: MovieClip > Sprite > DisplayObjectContainer > InteractiveObject > DisplayObject > EventDispatcher > Object.

Your MotionBrush class is of type MotionBrush , but it extends MovieClip , and by extension, all the classes listed in the inheritance chain. By typing the symbol parameter to DisplayObject , your SymbolCanvas class will also allow arguments for the symbol parameters that are Sprites, InteractiveObjects, and so on. This will

be of use if you ever decide to pass the SymbolCanvas class a source object that’s been instantiated using code rather than from the Library. As a general rule, typing

a parameter to the lowest class in the chain makes your code more flexible for future features.

The line inside the constructor, the initSymbolCanvas method call, passes the arguments to an initialization function. You may have noticed that in addition to being strictly typed, the second two parameters defined for the SymbolCanvas constructor method also have values assigned. In addition to setting default values for these parameters, these assignments cause the hideOriginalSymbol and clearCanvasOnUpdate param- eters to be optional. If these parameters are not passed when a new SymbolCanvas instance is created, the com- piler will not generate an error and the parameters will

be set to false and true, respectively, by default.

6. Let’s append the following initialization method just below the constructor block:

private function initSymbolCanvas(symbol: ➥ DisplayObject, hideOriginalSymbol:Boolean, ➥ clearCanvasOnUpdate:Boolean):void{

src = symbol;

Chapter 3 Introduction to ActionScript Classes

clearOnUpdate = clearCanvasOnUpdate; hideOriginal = hideOriginalSymbol;

initBitmap(); if(hideOriginal) src.visible = false; }

Conditional Logic

Conditional statements are used to determine if or Note that the parameters are exactly the same as those

when particular blocks of code should be executed. of the constructor. You’ll then use the arguments from the three parameters to assign values to your src ,

clearOnUpdate , and hideOriginal if statement is one of the most basic pieces

The

of programming logic. The if statement only will then call another initialization method to generate

properties. Your code

executes the code inside its code block if the your bitmap. If it happens that hideOriginal resolves to

conditions inside its parentheses are found to be

a value of true, your code will render the source object true. No curly braces are necessary to enclose an if invisible. statement if the code block is only a single line (see the SymbolCanvas class for an example of a

7. Now for some slightly more complex code (one rea- single-line if statement). son you’re encapsulating it in the SymbolCanvas

class). Add the following method below the primary The counterpart to the if statement is the else initSymbolCanvas method that you just added:

statement. An else statement must immediately follow an if statement. The code contained in

private function initBitmap():void { an else block will execute if the conditions for var targ:MovieClip = src.parent as MovieClip;

the if statement are found to be false. Similarly, bmd = new BitmapData(src.stage.stageWidth,

there is also an else - if statement that you can use to test for additional conditions (see the

➥ src.stage.stageHeight, true, 0xffffff); BoundedMover class later in this chapter for an bmp = new Bitmap(bmd);

example of the else - if statement). bmp.cacheAsBitmap = true; offset = targ.globalToLocal(new Point(0, 0)); bmp.x = offset.x; bmp.y = offset.y;

targ.addChildAt(bmp, targ.getChildIndex(src)); }

Let’s walk through the initBitmap method line by line. You first create a local variable named targ to store the parent of your source object. The parent is the object

inside which your source object is nested (this will likely be the root of the Flash document). Your code then uses the as keyword to tell the compiler to type this existing object as a MovieClip. This is necessary to access methods within the MovieClip class without gen- erating errors. At the moment, targ is a local variable, meaning it is assigned using the var keyword within the initBitmap method and will cease to exist once the

Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques

method has completed execution. Use local variables when possible to increase the speed at which your code executes.

Next, your code assigns the bmd property to a new BitmapData object. Every object onscreen has a refer- ence to the Stage stored in the stage property. You then use that reference to set your new BitmapData object’s width and height properties to match those

of the Stage within the first two arguments passed to the BitmapData constructor. With the third argu- ment, you’re assigning the transparent property of the BitmapData to true, which is essential for your effect to render properly. With the last argument you set the fill color to a hex value representing white (since the BitmapData instances use transparency, you will not see the white).

In the next line, you then assign your bmp property to a new Bitmap object and pass your BitmapData object to the Bitmap object’s constructor. The line following that turns on the cacheAsBitmap property for the Bitmap object. It may sound redundant to cache a bitmap as a bitmap, but it will be necessary if the bitmap canvas will

be used for any advanced masking in the future. The next three lines ensure that the bitmap starts at

the top-left corner of the Stage, even if your source symbol’s parent does not. A Point is a very basic object: just an x coordinate and a y coordinate. The new Point starts out with both x and y at 0 (the top-left corner of the Stage), and uses the globalToLocal method of the targ object to offset the coordinates based on the targ object’s position on Stage. After the coordinate space of the Point object has been adjusted, the x and y values are assigned to the Bitmap object (Figure 3.21).

Figure 3.21 The small purple square is nested inside the larger blue square’s symbol. The local position of the purple square is x:50, y:50. The local position of the blue square is also x:50, y:50. The position of the purple square relative to the Stage is therefore x:100, y:100.

Chapter 3 Introduction to ActionScript Classes

The last line within the initBitmap method adds your bitmap to the targ object’s display list so that it will be visible onscreen. Your code uses the addChildAt method to ensure that bitmap is rendered just underneath your source symbol. By using the getChildIndex method to then assign your bitmap to the stacking position held by the source object, the source object is pushed up a level in the display list (right on top of the bitmap).

8. Let’s fill in the update , dispose , and getBitmap methods with the following highlighted text:

public function update():void{ if(clearOnUpdate) bmd.fillRect(bmd.rect, 0); var matrix:Matrix = src.transform.matrix;

matrix.translate(-offset.x, -offset.y); bmd.draw(src, matrix, src.transform. ➥ colorTransform, src.blendMode); bmp.bitmapData = bmd; }

public function dispose():void{ bmd.dispose(); src.parent.removeChild(bmp); if(hideOriginal) src.visible = true; }

public function getBitmap():Bitmap { return bmp; }

The first line of the update method checks to see if clearOnUpdate is assigned a value of true, and if so, it clears the canvas using a simple fill. The second line stores the current matrix from the src object (which includes its position, scale, and rotation). The third line uses the translate method of the Matrix class, along with the offset point stored earlier, to determine where the src object should be rendered on the canvas (no matter how deep the source symbol is nested). Both the x and y coordinates have a minus sign ( - ) to compensate for the translation of the canvas in the

Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques

initBitmap method. The fourth line renders an image of your source symbol onto the bitmap data using the transformation matrix that you translated, the color transform from the source symbol, and the blending mode from the source symbol, so it will appear as it does on Stage. The final line in the update method assigns the updated bitmap data to the bitmap object so it will render onscreen.

The dispose method is your housecleaning func- tion. The first line removes the data stored within the

BitmapData object (using the dispose method built into the BitmapData class) to free up memory. The sec- ond line removes the bitmap from the parent object’s display list so it will no longer be rendered onscreen. The last line of the dispose method checks to see if the hideOriginal property was assigned a value of true, and if so, restores the visibility of the source object.

9. Confirm that the following import statements are all included at the top of your script. Add any that are

missing: import flash.display.DisplayObject;

import flash.display.MovieClip; import flash.display.Bitmap; import flash.display.BitmapData; import flash.geom.Point; import flash.geom.Matrix;

The SymbolCanvas class so far should read as follows: package com.anim.fx {

import flash.display.DisplayObject; import flash.display.MovieClip; import flash.display.Bitmap; import flash.display.BitmapData; import flash.geom.Point; import flash.geom.Matrix;

class SymbolCanvas {

Chapter 3 Introduction to ActionScript Classes

private var offset:Point; private var bmd:BitmapData; private var bmp:Bitmap; private var src:DisplayObject; private var clearOnUpdate:Boolean; private var hideOriginal:Boolean;

public function SymbolCanvas(symbol: ➥ DisplayObject, hideOriginalSymbol:Boolean=false,

➥ clearCanvasOnUpdate:Boolean=true){ initSymbolCanvas(symbol,

➥ hideOriginalSymbol, clearCanvasOnUpdate); }

private function initSymbolCanvas(symbol: ➥ DisplayObject, hideOriginalSymbol:Boolean,

➥ clearCanvasOnUpdate:Boolean):void{ src = symbol;

clearOnUpdate = clearCanvasOnUpdate; hideOriginal = hideOriginalSymbol; initBitmap(); if(hideOriginal) src.visible = false;

private function initBitmap():void { var targ:MovieClip = src.parent as ➥ MovieClip; bmd = new BitmapData(src.stage. ➥ stageWidth, src.stage.stageHeight, true, 0xffffff); bmp = new Bitmap(bmd); bmp.cacheAsBitmap = true; offset = targ.globalToLocal(new Point

➥ (0, 0)); bmp.x = offset.x;

bmp.y = offset.y; targ.addChildAt(bmp, targ.getChildIndex

➥ (src)); }

public function update():void{ if(clearOnUpdate) bmd.fillRect ➥ (bmd.rect, 0);

Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques

var matrix:Matrix = src.transform.matrix; matrix.translate(-offset.x, -offset.y); bmd.draw(src, matrix, src.transform.

➥ colorTransform, src.blendMode); bmp.bitmapData = bmd;

public function dispose():void{

bmd.dispose(); src.parent.removeChild(bmp); if(hideOriginal) src.visible = true;

public function getBitmap():Bitmap { return bmp; } } }

You can now test the movie within your Flash document. Your symbol should now be drawing a path as it tweens (Figure 3.22).

The MotionBrush effect will also capture any animation inside your symbol.

Figure 3.22 The MotionBrush class applied to the rocket symbol.

Chapter 3 Introduction to ActionScript Classes

To create a write-on effect, try drawing a shape or writing your name with the Pencil tool. You can select the path cre- ated with the Selection tool, cut it (Command+X/Ctrl+X), select your tweened symbol, and paste the path to the

tween (Command+V/Ctrl+V). Test your movie again to see To explore the write-on effect further, check out the free Motion-

the effect (Figure 3.23). Sketch extension (in the Extensions folder on the included CD or at http://ajarproductions.com/ blog/2009/02/10/flash-extension- motionsketch/). MotionSketch can record your drawing in real time and translate it into a motion tween.

Using a MotionBrush Object as a Mask

To use your symbol as a mask, you must first give instance names to your “brush” symbol instance and the symbol instance that you will be masking. Then you can use the following code (applied as a

Figure 3.23 The MotionBrush class used as a write-on effect with a symbol class or on a frame) (Figure 3.24): containing a fire animation created using the Deco tool.

import com.anim.fx.MotionBrush;

The MotionTrail class

maskedInstance.cacheAsBitmap =

➥ true;

Now you’ll generate the first variation on the MotionBrush maskedInstance.mask = theme. For starters, let’s make the content painted onto

➥ MotionBrush(brushInstance).

the canvas fade as the source symbol moves farther away.

➥ getCanvas();

This will render a trail, giving the impression that your brush symbol is moving a little too rapidly for the eyes. This effect is frequently used to create a trail for mouse cursors.

1. Save a new version of your MotionBrush document as MotionTrailExample.fla.

2. Create a new class called MotionTrail.

3. Save the class file as MotionTrail.as in the examples/

Figure 3.24 This animation creates the

com/anim/fx directory.

effect of wiping fog off a window using the MotionBrush applied as a mask.

Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques

4. Update the first line in the script to reflect the proper package:

package com.anim.fx {

5. You will be attaching MotionTrail to the Library symbol you created just as you did with the MotionBrush class.

Update the class declaration so that your class extends MotionBrush:

public class MotionTrail extends MotionBrush {

6. The completed code for the MotionTrail class is con- siderably shorter than that of the MotionBrush class,

because much of the behavior is inherited from the MotionBrush class. Complete the MotionTrail class by adding the highlighted code as follows:

package com.anim.fx {

import flash.events.Event; import com.anim.fx.MotionBrush;

public class MotionTrail extends MotionBrush {

public var fadeAmount:Number = .5;

public function MotionTrail() {

init(); }

protected override function init():void { hideSymbol = false; clearCanvasOnUpdate = false;

initStageListeners();

protected override function ➥ onFrame(e:Event):void {

symbolCanvas.fade(fadeAmount); super.onFrame(e);

Chapter 3 Introduction to ActionScript Classes

Note that the hideSymbol and clearCanvasOnUpdate properties are assigned a value of false. Given that the MotionTrail will be manipulating the canvas, you’ll keep the original symbol visible. Otherwise, the init function is identical to the init function in the Motion- Brush class. Also, note the use of the override keyword to rewrite the init function.

The onFrame method is also overwritten in the Motion- Trail subclass. The first line within the onFrame method calls a fade method on the SymbolCanvas instance that you will write in a moment. You’ll pass the fadeAmount property value to the fade method. This will determine how much of the canvas’s alpha value is faded on each new frame. Note that the fadeAmount property is public, meaning that this value can be assigned from any other part of your movie.

The second line in the onFrame method uses the super keyword to reference the onFrame method in the

MotionBrush superclass and passes the event received by the overwriting onFrame method. In effect, you are aug- menting the original onFrame method by adding a piece of functionality to the method and then running it as it normally would run inside of a MotionBrush instance.

7. Save your MotionTrail class and return to the Sym- bolCanvas class in the Code Editor. Add the following

method toward the bottom of the SymbolCanvas class: public function fade(alphaMult:Number=.5):void {

if(clearOnUpdate) return; var cTransform:ColorTransform = new ➥ ColorTransform(); cTransform.alphaMultiplier = alphaMult; bmd.colorTransform(bmd.rect, cTransform); }

This is the fade method that was referenced from the MotionTrail class. The fade method accepts one argu- ment representing a value for how much transparency to apply on each frame. The closer the number is to

0, the more quickly the trail will fade out. The default value for this parameter is .5.

Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques

The first line inside the method checks to be sure that clearOnUpdate is not set to true; if it is, the code

uses the return keyword to abort the function. Since clearOnUpdate will wipe the canvas clean each time the update method is executed, there would be no reason to adjust the transparency on a clean canvas, so there’s no need to waste the processing power.

The second line within the fade method gener- ates and stores a new ColorTransform object. In the third line, you apply the received argument to the alphaMultiplier property of the ColorTransform object. The last line then applies the ColorTransform to your BitmapData object, thus fading the entire image. The longer a particular representation of your symbol is onscreen, the more fades it will go through. Each fade will have an additive effect, rendering the older representations lighter than the new ones. The higher the alphaMultiplier property is set, the quicker the trail will fade.

8. Make sure that the following import statement has been added to the SymbolCanvas class:

import flash.geom.ColorTransform;

9. Save your SymbolCanvas class and return to the MotionTrailExample.fla document.

10. Open the Symbol Properties for your symbol and update the Class field to read com.anim.fx.MotionTrail.

11. Test your movie (Figure 3.25).

Chapter 3 Introduction to ActionScript Classes

Figure 3.25 The MotionTrail class applied to the rocket symbol.

Try adjusting the fadeAmount property in the Motion- Trail class and observe how the trail is altered (try values between 0 and 1). Note that the MotionTrail class is just as (if not more) complex an effect as the MotionBrush. But since the MotionBrush class was already written, it took significantly less effort to get the MotionTrail class off and running.