AS3: MovieClip.addFrameScript

by troy on September 22, 2007

MovieClip.addFrameScript is a very powerful way to decouple script from the timeline. This post help you understand how it works.

When movies are compiled (including the top level swf), if no class is provided. Flash creates one for you behind the scenes. 1 Class is created per 1 MovieClip, typically sharing the same name. It helps to understand how the conversion happens, to make best use of it, and writing code on the timeline in general.

  1. imports are only needed once in a timeline
  2. variables declared on a frame, end up as class variables,
  3. you can't redeclare variables on multiple frames.
  4. only one function is called per frame, this can be tweaked, overridden or amended with addFrameScript

You can't redeclare variables,

on frame1 and frame2 put:
var aName:String = "A";
will give you the following error:
1151: A conflict exists with definition aFrame in namespace internal.

however putting on Frame 1

var aName:String ="A"; //frame1

and on Frame2

aName = "B" //frame2

works fine.

MovieClip.addFrameScript

Is the undocumented glue between the timeline frame and the class's function ( if bound). There can only be one script/function bound to a frame using the built in addFrameScript, though an alternative approach is to poll currentFrame changing (via Event.ENTER_FRAME).

This binding happens via addFrameScript(frameNumber-1, functionToCall...); Note that the first argument is ZERO BASED (while normally the timeline is 1 based)
During the Fla.compilation our script gets put into a function like:

Class Test_fla{

function frame1():*{

var aName:String = "A";

}

function frame2():*{

aName = "B";
}
}

The important thing to note is the frame1...frameN naming, where N is the frame number 1-whatever, We can validate this by decompiling the swf, using the AbcDump utility, which takes our test.swf and outputs:

function Test_fla::frame1():* /* disp_id 0*/
{
// local_count=1 max_scope=1 max_stack=2 code_len=16
0 getlocal0
1 pushscope
2 findpropstrict trace
4 pushstring "onFrame1"
6 callpropvoid trace (1)
9 findproperty aFrame
11 pushstring "aFrame"
13 initproperty aFrame
15 returnvoid
}

So the end will be a frame to function mapping (which we can't see) like:

  • [0]= frame1()
  • [1]= frame2()

Note again the frameNumber is zero based, while the script is 1 based.

Consequences

which has 2 consequences,

  1. you can't name your own functions frameN if one already exists. This is the same error as compiling in the same *.as:
    function frame1(){

    }

    function frame1(){

    }

  2. you can call and over ride these functions,
    addFrameScript(0, overrideFrame1);
    function overrideFrame1():*{

    //do something before
    frame1();
    //do something after
    }

In addition the top level Class, will be shared across different scenes, but these can have on the timeline different configuration values (say which language to use), and when used with jsfl to publish all scenes, create a handful of starter files.

Conclusion

This is kick ass for completely separating a UI.swf from a Controller.swf Keeping designers working on the timeline, and coders out of the design.

For the coders, and others working in Flash, is the ability to use addFrameScript to perform actions when a frame is fully initialized and children are on stage, similar to onLoad() in AS2, where-as use of ENTER_FRAME gets called prior to children in that movieclip getting called...this is similar to onInit() in AS2. So for example you can have a button only on a particular frame and setup it's event listener to call your controller...in another swf, regardless of what the playhead is doing.

In someways I find this cleaner than watching using addedToStage, rendered etc.

REFERENCES:

[1] Senoculars post
[2] FlashGurus info as Senocular
[3] BIG SPACESHIP, Extending addFrameScript to use the frame labels instead of framenumbers... the same glue I'm using as well, though I'm more interested in events being generated, than script.

[4] an alternate approach on evilzug's journal using ENTER_FRAME


You should be aware if using that approach that when the framescript is called via the ENTER_FRAME, items in the frame may have not been added yet, so this approach can't be used to bind to objects on the timeline (e.g. to registerListeners to buttons), this the addFrameScript does not suffer from.

Here's an output with one on the timeline the other added via oizys's frameScript approach:


entered frame 3
onReachedInstructions instructions null <- no button yet, via modified addFrameScript
timeline reached instructions [object SimpleButton] <- normal addFrameScript
onReachedInstructions instructions [object SimpleButton] <- now the button exists

{ 0 comments… add one now }

Leave a Comment

 

{ 2 trackbacks }

Previous post:

Next post: