Adding ActionScript Dynamically to Frames with addFrameScript() in AS3
addFrameScript, both powerful and undocumented, is an ActionScript 3 method supported by instances of the MovieClip class. It is inherently part of the way that Flash creates SWFs, which means that, while it is undocumented, it will likely be with us for some time.
To start, let's define the pain:
- When coding in Flash, it is generally optimal to remove as much code as possible from your timelines (if you don't know that yet, then just trust me)
- AS3 symbol linkage and the document class make it very easy to move *a lot* (but not all) of your code to external files
- But, using these techniques, it is not really possible to remove *all* code from your timelines, since code in class files is effectively on frame 1 of your linked timeline. For example, let's say you need to place a 'stop()' action on frame 10. How do you do that in a class file?
So, the solution -- the method you need to know in order to move *ALL* code from your FLAs to external class files -- is addFrameScript(). It's a really simple method.
someMovieClip.addFrameScript(aFrameNumber,aFunctionToRun);
In this example, we are saying:
- When the MovieClip with the instance name someMovieClip
- hits frame number aFrameNumber
- run the function named aFunctionToRun
And voila! It's that simple. Two notes:
- Frame numbers in addFrameScript are 0-based, if you want to put a function on frame 1, you'd call addFrameScript with the number 0.
- The function you call (aFunctionToRun in the above example) is treated just like a regular function -- not like a callback function on an event. That means the function expects no arguments.
Take the following example (in the folder named 'byFrameNumber' in the attached ZIP), in which we have a main timeline that contains a MovieClip instance with the instance name of mc. Let's assume we want to tell mc to stop on its final frame. Here's the code.
On the timeline
//tell mc to run stopMe when it hits its final frame (the measure is 0-based) mc.addFrameScript ( mc.totalFrames - 1 , stopMe ) ; //stopMe is called on the final frame of mc, but it is not a 'callback' function stopMe ( ) { //tell mc to stop ( ) ; mc.stop ( ) ; }
In a class file
package { import flash.display.MovieClip; public class AddFrameScriptSample extends MovieClip { public function AddFrameScriptSample() { //tell mc to run stopMe when it hits its final frame (the measure is 0-based) mc.addFrameScript(mc.totalFrames-1,stopMe); } //stopMe is called on the final frame of mc, but it is not a 'callback' //it MUST be public public function stopMe():void { //tell mc to stop mc.stop(); } } }
After looking through this code and learning addFrameScript, you might ask 'is there any way to work with frame labels rather than frame numbers'? Why yes, Virginia, there is. To do that, we need to work with the currentLabels property of the MovieClip class.
currentLabels is an array of 'FrameLabel' objects -- so, for each frame on your MovieClip's timeline, there will be a FrameLabel object created and inserted into the currentLabels array.
A FrameLabel consists of a name (the string identifier of the frame label) and a frame (the 1-based number of the frame that contains the label stored in name). NOTE: that the frame property is 1-based, while addFrameScript expects 0-based frame numbers. So you need to account for that.
So, in the sample code contained in the folder named 'byFrameLabel' in the attached ZIP, we have a MovieClip on our stage, with an instance name of mc, and it contains a multi-frame tween, with four labeled frames. This code tells that mc MovieClip to stop on any frame that has a label, and to resume when the stage is clicked.
On the timeline
//create an array of all frame labels in the mc MovieClip var aLabels = mc.currentLabels; //for each label in the array for each (var n in aLabels) { //trace out the name and frame number of the frame label trace( n.name + " @ " + n.frame ); //add a call to stopMe() on each frame with a label mc.addFrameScript( n.frame - 1 , stopMe ); } //start listening for the mouseDown event anywhere in our movie, calling onDown as the callback stage.addEventListener( MouseEvent.MOUSE_DOWN , onDown ); //called as callback from mouseDown event on stage function onDown( evt ) { //tell the mc MovieClip to play mc.play( ); } //called by assignment with addFrameScript, by every frame of the mc MovieClip with a label function stopMe( ) { //tell the mc MovieClip to stop mc.stop( ); //trace what frame the mc MovieClip is on trace( "stopping at frame " + mc.currentFrame ); }
In a class file
package { import flash.display.MovieClip; import flash.events.MouseEvent; public class CurrentLabels extends MovieClip { //-------------------------------------- // CONSTRUCTOR //-------------------------------------- public function CurrentLabels(){ //create an array of all frame labels in the mc MovieClip var aLabels = mc.currentLabels; //for each label in the array for each (var n in aLabels) { //trace out the name and frame number of the frame label trace( n.name + " @ " + n.frame ); //add a call to stopMe() on each frame with a label mc.addFrameScript( n.frame - 1 , stopMe ); } //start listening for the mouseDown event anywhere in our movie, calling onDown as the callback stage.addEventListener( MouseEvent.MOUSE_DOWN , onDown ); } //-------------------------------------- // PUBLIC METHODS //-------------------------------------- //called by assignment with addFrameScript, by every frame of the mc MovieClip with a label public function stopMe ( ) : void { //tell the mc MovieClip to stop mc.stop ( ) ; //trace what frame the mc MovieClip is on trace ( "stopping at frame " + mc.currentFrame ) ; } //-------------------------------------- // EVENT HANDLERS //-------------------------------------- //called as callback from mouseDown event on stage private function onDown ( evt : MouseEvent ) : void { //tell the mc MovieClip to play mc.play ( ) ; } } }
Share and enjoy!


