AS Reference  :  Notes Index  :  Resources  :  About/Contact  :  Downloads

Initiating a series of tweens when a control is clicked

Previously we looked at using the Tween class to ease an object across the stage. In this sample, we'll look at using the onMotionFinished event property of that class to cause something to happen when the tween is complete. As you can see above, clicking one of the controls causes a series of things to happen: the current caption and color strip disappear, a new picture (the one corresponding to the button) slides in, the colored strip (colored to match the button) slides to the right, and a corresponding caption fades in.

Parts of the movie

The main part of this movie is a movieclip (offstage initially) with instance name faces, which holds four movieclips arranged in a rectangle (but could be in any arrangement and the code would still work): p0, p1, p2, and p3. They are named this way to correspond to elements of two arrays we'll use, colors and captions. Because the first element of an array is always 0, we append a 0 to the name of the first movieclip, a 1 to the second, etc. Later, we'll look at using classes to define the behavior and relationships between the movie parts, but for now, we'll keep track of the relationships by numbering. The button that controls each movieclip in the faces movieclip has a name (c0, c1, c2, or c3) corresponding to that of the movieclip it controls, the element of colors which corresponds to it, and the element of captions that corresponds to it. For example, c0 controls p0, its color is stored in colors[0] and its caption is stored in captions[0]. This could be extended to any number of controls and movieclips -- I just chose four to keep things simple. On the stage, above the faces layer, is a mask movieclip maskmc in the shape of one of the pictures. When a control is clicked, it will move faces to a point where the corresponding picture shows under the mask.

A note about the caption font

In addition to the 4 controls and movieclips, there is one colored strip (instance name strip) set to alpha 80% and one caption movieclip with a dynamic textfield named _txt in it. The font in that dynamic textfield is Georgia, which I embedded, to make sure it is visible for users who don't have the Georgia font installed. This is necessary to do for any font used in a dynamic textfield that a visitor to your site might not have, or the textfield will not be visible to them. In this case, it's also necessary to embed the font because I want to tween (fade) it in, and that requires embedding for dynamic text. In the IDE, you can embed the font by selecting the textfield, clicking the Character button in the Properties panel, choosing Specify Ranges, and shift-clicking any of the entries that contain characters which may be in your textfield. Click OK to embed those characters. Alternately, you can use a device font, which will cause the user's default installed font of the type selected (serif, sans, or typewriter) to be used. You lose control over the exact size and position of the font when you select that option, but it keeps the file size down. Notice that embedding the font does not make it available in the fla, so if you pass your fla on to someone else to work on, they must have the font installed on their machine (or choose an alternate) in order to republish it and have the font show.

Controls

Each control is made up of two movieclips: inner_mc and outer_mc, which are turned on and off for different mouseover events:

Each of those can be set up with multiple assignment statements like:

c0.onRelease = 
c1.onRelease = 
c2.onRelease = 
c3.onRelease = function() {
   this.inner_mc._alpha = 100;
}

or in a loop:

for (var i:Number=0; i<4; i++) {
   this["c"+i].onRelease = function() {
      this.inner_mc._alpha = 100;
  }
}
using associative array syntax as discussed in the yellow box on this page. Note that this["c"+i] refers to the controls c0-c3 on the main timeline (this = main timeline). Inside the function, which is assigned to that control, "this" refers to the control, so this.inner_mc refers to the movieclip inner_mc of the control that has just been clicked. Code to set up the controls with the above functionality is available in faces_start.fla (link at right under Files).

Adding a tween

Here is the code that needs to be added to faces_start.fla to make the corresponding picture slide in under the mask. At the start of the movie, we need to import the easing and transition classes, and set up a variable accessible everywhere on the main timeline to keep track of which picture was last clicked:

import mx.transitions.Tween;
import mx.transitions.easing.*;

var whichPic:Number;

And this code in the onRelease handler causes the selected picture to slide into place:

whichPic = Number(this._name.substr(1));
new Tween(faces, "_x", Strong.easeOut, faces._x, maskmc._y-faces["p"+whichPic]._x, 30, false);
new Tween(faces, "_y", Strong.easeOut, faces._y, maskmc._x-faces["p"+whichPic]._y, 30, false);

Tween timing: the movie is set to 20fps, so the two parameters at the end of the Tween statement make the tween last for 30 frames (one and a half seconds).

Tween position: The x and y values of faces required to end up with a particular movieclip (p0,...p3) showing through the mask is the mask position minus the picture position within faces. Eg, for p0 the ending point is maskmc._x-faces.p0._x, which can also be written as maskmc._x-faces["p"+0]._x, or more generically for any p: maskmc._x-faces["p"+whichPic]._x.

Making something happen when the tween ends

This is the crucial step in this exercise: making something happen when the tween is over. To do that, we need to assign a function to the tween object's onMotionFinished event property (the same as we assign functions to the onRollOver, onRelease, etc properties of MovieClips). So we'll create an object on the main timeline, assign one of the tweens to that (we don't need to create separate objects for the x and y tween because they should both be over at the same time), and assign a function to that object's onMotionFinished property. Here is the code for that. At the start of the movie, in the variable declaration section that we began above with the creation of whichPic:

var picSlideTween:Object;

(Creating an instance of type Object for something which should really be of type Tween is a hack to keep the compiler from throwing an error in Flash MX 2004 when you assign a function to its onMotionFinished property, which the compiler doesn't recognize as a property of the Tween class. That problem has been fixed in Flash 8.)

And inside the onRelease function for the controls:

strip._xscale = 0;
picSlideTween = new Tween(faces, "_x", Strong.easeOut, faces._x, maskmc._x-faces["p"+whichPic]._x, 30, false);
picSlideTween.onMotionFinished = function() {
   new Tween(strip, "_xscale", Strong.easeOut, 0, 100, 15, false);
}

(Assigning a function to onMotionFinished here instead of prior to starting the tween, as would normally be done for a callback routine, is necessary because there is no way to create an actual instance of the Tween class without also setting it in motion, and therefore no way of assigning anything to it prior to that.)

Making named functions to handle the tween events

The above code works, but is would be neater if we made separate functions on the main timeline to handle each tween event and assigned those to the tween object event property. Here we'll add a colors array, a color object, a tween object for the stripOpen tween, and set up the strip slide function to change the color of the strip and slide it in. On the main timeline:

// create an array of colors that correspond to each button (to set the strip color)
var colors:Array = [0xffffff, 0xE4D9B9, 0x9CA4BA, 0xC60733];

// create tween objects to assign onMotionFinished handlers to below
var picSlideTween:Object;
var stripOpenTween:Object;

// assign a color instance to the strip for setting its color below
var stripcolor:Color = new Color(strip);

function onPicSlideDone() {
   // set the strip color and slide the strip in
   stripcolor.setRGB(colors[whichPic]);
   stripOpenTween = new Tween(strip, "_xscale", Strong.easeOut, 0, 100, 15, false);
}

And this change in the onRelease function:

picSlideTween.onMotionFinished = onPicSlideDone;

Steps to finish the movie

An array captions is added to hold the captions that should be displayed with each picture. A captionFadeInTween object is declared, to handle actions that should be done after the caption has faded in.

In the same way we added a function to handle the strip sliding open (once the picture had slid in), we'll add a function to fade in the text and assign that to stripOpenTween.onMotionFinished.

When a control is clicked, a new sequence is started if the new selection is different from the current one. That new sequence consists of stopping the current tweens, setting the caption mc alpha to 0, the caption text to '' (blank), the strip color to the new color, and starting the picture slide tween. The rest is handled by the onMotionFinished handlers as each tween ends. This is the onRelease code for the controls:

this["c"+i].onRelease = function() {
   this.inner_mc._alpha = 100;
   // don't do anything if user clicks same control twice
   if (whichPic != Number(this._name.substr(1))) {
      // stop all tweens
      picSlideTween.stop();
      stripOpenTween.stop();
      captionFadeInTween.stop();		
      // hide caption
      caption._alpha = 0;
      caption._txt.text = '';
      // reset the strip width to 0
      strip._xscale = 0;
      // get the number which identifies this clip (from its name)
      whichPic = Number(this._name.substr(1));		
      // start new tween sequence
      new Tween(faces, "_y", Strong.easeOut, faces._y, maskmc._y-faces["p"+whichPic]._y, 30, false);
      picSlideTween = new Tween(faces, "_x", Strong.easeOut, faces._x, maskmc._x-faces["p"+whichPic]._x, 30, false);
      picSlideTween.onMotionFinished = onPicSlideDone;
   }
};

The complete code for the movie may be seen in faces_tweensequence.fla (link at right under Files).

Recursive calls to set up a tween sequence for a series of objects

To set up a series of objects to say, fade in sequentially, recursive calls can be made to a function that checks to see where in the series it is currently and starts a new tween (using the same tween object) if not at the end. This is the code to produce the tween sequence in the above example, which contains movieclips dot0 - dot5, all set to alpha 5% in the IDE initially, in a movie running at 20fps:

import mx.transitions.Tween;
import mx.transitions.easing.*;

// sequence of movieclips to be tweened (needn't be named numerically)
var tweenObjects:Array = ["dot0", "dot1", "dot2", "dot3", "dot4", "dot5"];
// pointer to object currently tweening
var iTweenObject:Number;
var theTween:Object;
var timeline:MovieClip = this;

function init() {
   iTweenObject = -1;
   for (var i:Number=0; i<tweenObjects.length; i++) this[tweenObjects[i]]._alpha = 5;
   startTween();
}

function startTween() {
   // are we at the end of the sequence?
   if (++iTweenObject < tweenObjects.length) {
      // no, start a new tween
      theTween = new Tween(timeline[tweenObjects[iTweenObject]], "_alpha", Regular.easeOut, 5, 99, 20, false);	
      theTween.onMotionFinished = startTween;
   } 
}

And this is the code to activate/reactivate the sequence:

againbtn.onRelease = function() {
   theTween.stop();
   init();
}

Going one step further, here is a revised neater version of the above which gets rid of the need for a timeline variable (which was necessary because assigning startTween to theTween.onMotionFinished makes the scope of startTween theTween instead of the current timeline) by employing the ever-useful Delegate class:

import mx.transitions.Tween;
import mx.transitions.easing.*;
import mx.utils.Delegate;

// sequence of movieclips to be tweened (needn't be named numerically)
var tweenObjects:Array = ["dot0", "dot1", "dot2", "dot3", "dot4", "dot5"];
// pointer to object currently tweening
var iTweenObject:Number;
var theTween:Object;

function init() {
   iTweenObject = -1;
   for (var i:Number=0; i<tweenObjects.length; i++) this[tweenObjects[i]]._alpha = 5;
   startTween();
}

function startTween() {
   // are we at the end of the sequence?
   if (++iTweenObject < tweenObjects.length) {
      // no, start a new tween
      theTween = new Tween(this[tweenObjects[iTweenObject]], "_alpha", Regular.easeOut, 5, 99, 20, false);	
      theTween.onMotionFinished = Delegate.create(this, startTween);
   } 
}

againbtn.onRelease = function() {
   theTween.stop();
   init();
}

Perpetual Motion

To set up an object in perpetual motion (eg, moving back and forth between two points), the onMotionFinished function must check to see which direction the object has just gone in, and send it in the other direction, using a variable (goingRight in our example) to track the current direction. With object ball_mc on stage, this code will do that:

import mx.transitions.Tween;
import mx.transitions.easing.*;

var LEFTBOUND:Number = 20;
var RIGHTBOUND:Number = 344;
var goingRight:Boolean = true;
var tween_handler:Object;

// create the function to check direction, start a new tween, and toggle the flag
function changeDirection() {
   if (goingRight) tween_handler = new Tween(ball_mc, "_x", Regular.easeInOut, RIGHTBOUND, LEFTBOUND, 2, true);
   else tween_handler = new Tween(ball_mc, "_x", Regular.easeInOut, LEFTBOUND, RIGHTBOUND, 2, true);
   goingRight = !goingRight;
   // must do this again because creating a new Tween wipes out the old property
   tween_handler.onMotionFinished = changeDirection;
}

// start things going
tween_handler = new Tween(ball_mc, "_x", Regular.easeInOut, LEFTBOUND, RIGHTBOUND, 3, true);
tween_handler.onMotionFinished = changeDirection;

Intro
Flash: What & How
Example Sites
Create
Draw, Edit Shapes
Gradients
More Drawing Tips
Import
A Sample
Animate
Frames, Keyframes
Motion Tweens
More Motion Tweens
Shape Tweens
Masks
Control
Stop/Replay
Movieclips Intro
Movieclip Reference
Site Structure 1
Slideshow Movieclip
Contact Form
Scroll Resume
Preloader
Site Structure 2
Publish
Display Options
Player Detection
Optimize
AS 2.0 Basics
Intro to Syntax
Playhead Commands
Playhead Cmds 2
Coded Tween
onEnterFrame
Intro to Classes
Declare/Assign
Comments, Trace
Simple Data Types
Arrays & Objects
Code Blocks
Operators
Beyond Buttons
Code Structure
Toggle Controls
Group of Buttons
Drag and Hit
Distort Magnifier
Scroll Text
Bee Game
Dart Shooter
Sound Control
Easing Slider
Easing Slider 2
Components Intro
Timers & Delays
Dynamic Content
Intro
Drawing API
Create Text
Attach Movieclips
Easing Slider 3
Easing Slider 4
Load jpg/swf
Sliding Viewer
Preload swf
XML
Easing Slider 5
Server Comm
LoadVars (w/ PHP)
AS - PHP Lookup
Text File
Database 1:LoadVars
Database 2:Remoting
Read from directory
AS 2.0 Classes
Intro
Math
Key
Date
Color
EventDispatcher
New Samples
Pie Chart
Event-model Emailer
Tween Sequence
Fuse Sequence
SVG in Flash
Bitmap Topo
SWF as Data Holder
Two-level Menu
Yahoo! Flash Maps
Class-based Game
ASTB Samples
Disclaimer
3D Outlines
Bounce Collide
Address Book
Save Drawings
Home  :  Notes Index  :  Resources  :  About/Contact  :  Downloads