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
_totalframes; in AS3,
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.
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); (
instanceof in AS3). Test your movie and keep an eye on the Output panel. Sure enough, Output panel says
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
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:
Note that only the object reference,
this.parent, goes inside the parentheses. The new combined expression,
.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.