Trust Me, AS3, It’s a MovieClip

ActionScript 3.0 Flash

This topic came up when someone asked me how (if it was possible) to instruct one movie clip to start playing after another has stopped.  For example, the main timeline does its thing, humming along, when it suddenly comes to a keyframe that contains a nested movie clip.  A simple stop() action in that keyframe tells the main timeline to rest where it is, and the nested movie clip starts playing on its own.  When the nested clip hits the last frame of its own timeline … that’s when the main timeline needs to start moving again.  How to do that?

In my reply, I said there were a number of possible ways.  You could set up a loop, for example — MovieClip.onEnterFrame (AS2) or Event.ENTER_FRAME (AS3), maybe setInterval() (AS2) or the Timer class (AS3) — and in that loop, check the current frame of the nested movie clip against the number of its total frames.  In AS2, that would be a comparison of _currentframe to _totalframes; in AS3, currentFrame to totalFrames.  When the former equals the latter, invoke MovieClip.play() on the main timeline and quit the loop.

But much easier than that, and less processor intensive, is simply to put a keyframe script in the last frame of the nested movie clip, telling its parent (the main timeline) to play.  In AS2, that would be this._parent.play();.  In AS3, this.parent.play(); (no underscore on parent).  Ah, but there lies a problem.  The AS3 version, which is technically correct, causes a compiler warning:  1061: Call to a possibly undefined method play through a reference with static type flash.display:DisplayObjectContainer.  What on earth? 

What’s going on?

Thankfully, that error message gives a very useful clue.  Forget the cryptic 1061, forget “static type” blah blah.  The useful parts are “undefined method play” and “DisplayObjectContainer.”  Essentially, this is saying, “Hey, you’re pointing me to an instance of the DisplayObjectContainer class and asking me to invoke a play() method on it.  There is no play() method in this class, bub, so what am I supposed to do?”

If you look up the DisplayObjectContainer class in the ActionScript 3.0 Language and Components Reference, you’ll find that indeed, the class doesn’t support the method play().  That’s a MovieClip method.  But wait … shouldn’t the expression this.parent — as stated by a movie clip in the main timeline — point to a valid MovieClip reference?  To be fair, DisplayObjectContainer is indeed an ancestor in MovieClip’s family tree.  MovieClip extends Sprite, which extends DisplayObjectContainer, but the main timeline certainly is a movie clip.  In fact, you can prove it.

Create a new ActionScript 3.0 FLA, draw a quick shape and convert it to a movie clip symbol.  Enter its timeline and, in frame 1, type trace(this.parent is MovieClip); (is replaces instanceof in AS3).  Test your movie and keep an eye on the Output panel.  Sure enough, Output panel says true.

So what gives?  If the expression this.parent points to a valid MovieClip instance, why isn’t Flash smart enough to allow for the invocation of a MovieClip method, such as play(), on that instance?  Honestly, that’s a good question.  It’s so good, I can’t answer it.  But I do know how to get around it.  ;)

The “unsafe” workaround

That overly cautious error message is the result of Flash CS3’s default strict mode for the compiler.  I don’t recommend the following change, but if you simply want to turn off the warning (along with a bunch of other useful warnings, all in one shot), head over to File > Publish Settings > Flash tab, then click the Settings button.  Remove the checkmark from Strict Mode and you’re done.  Test your code and it’ll work just fine — because (in this context) this.parent really is a MovieClip reference.

Again, experiment with that if you like, but I really don’t recommend it.  By turning off strict mode, you may be tempting yourself to write lazy code, and sooner or later, especially in AS3, that will bite you with a set of sharp teeth.  And it’ll happen on a day when your boss is breathing down your neck.

The better workaround

I call this one “better” because, by using it, you end up demonstrating that you know how to be sensitive to the compiler, paranoid as it may occasionally be.  The better you know what the compiler needs, the likelier you’ll master the language.

We already know, even if the compiler doesn’t seem to, that the expression this.parent — in this context! — does refer to a MovieClip instance.  We’re simply going to tell the compiler that.  By casting that expression as a MovieClip, you’re effectively saying, “Trust me on this one; this is a MovieClip.”  Casting is done like this:

MovieClip(this.parent).play();

Note that only the object reference, this.parent, goes inside the parentheses.  The new combined expression, MovieClip(this.parent) gets .play() (with the leading dot) tacked on to the end, and even with strict mode on, that’ll do it.

That goes for any MovieClip class member, by the way, not just play().  All the cast does is let the compiler know it’s truly dealing with a MovieClip, so any MovieClip feature is covered.

Leave a Reply