Adobe, MAKE SOME NOISE

There are a handful of questions that get posted over and over again in the forums that all boil down to the same issue: setting up instance names in AS3 doesn't work.

Everyone who hits this problem comes up with a plan of attack that goes something like this:

  1. for(i = 0; i < 5; i++){
  2. var mc:MovieClip = new MovieClip();
  3. mc.name = "mc" + i;
  4. addChild(mc);
  5. }
  6.  
  7. mc3.play();

Which sounds pretty good on paper, but generally ends with this:

  1. Error 1120: Access of undefined property mc3.

So what went wrong? This is easily one of the biggest stumbling blocks for new AS3 users, and Adobe goes to great lengths to ignore it and pretend the problem doesn't exist. Here's the secret: Instance names don't really exist!

Ok, more specifically, when you assign an instance name in Flash, there is secret code generated for you behind the scenes that creates two variables which work together to give you the perception of an instance name. To do the same thing in your own code you would use this:

  1. public var mc3:MovieClip = new MovieClip();
  2. mc3.name = "mc3";

A .name is not a thing

The first half of this solution is repairing a misconception; There is a general belief that setting the name property on an object gives it mystical powers. It doesn't. The name is just a string that is attached to objects for your convenience, it is not a unique identifier. Saying you want to play the clip named "mc3" is just as silly as saying you want to play the clip at .x = 50, or .alpha = 1 – these are all attributes of objects, not pointers to the objects themselves.

So with all of that said, now it's time to contradict myself. Adobe has tried to redeem themselves by making a little workaround function for this problem. It comes in the form of the getChildByName("mc3") method. It's not particularly efficient and you can have multiple things share one name so it's not great code practice, but it is a handy tool to be aware of in a pinch.

Create dynamic variables at runtime

Having completely debunked .name, we've now got the other half of this issue to deal with - how to create dynamic vars in AS3. Again the answer is, you can't. What you can do, is leverage a single Array to point at all your clips at once.

  1. var clips:Array = [];
  2.  
  3. for(i = 0; i < 5; i++){
  4. var mc:MovieClip = new MovieClip();
  5. mc.name = "mc" + i;
  6. addChild(mc);
  7. clips[i] = mc;
  8. }

That code will create 5 distinct MovieClips and stick them all into the clips Array under different indices. To get a specific clip back later, you just have to know the index:

  1. clips[3].play();

⇠ AS2 to AS3: Calling a Method of a .parent Class (1 of 2)

And now - the thrilling conclusion!

So, The Easy Way is great for getting your project working and out the door - however it's the opposite of great for writing re-usable code and observing happy OOP best practices. If you're asking "why?," well here's the answer: you're breaking the chain of command. The child class should never (ever!) be issuing commands to the parent – the most it should do is alert the parent to any changes and let the parent be the judge of what to do.

For the sake of argument, let's say that your child class is a pre-loader and your parent class is the main movie. When that loader hits 100%, it's going to kick the main timeline in the ass and start the playhead immediately. Depending on your setup, that might be ok - but imagine we also have a fancy loading animation on screen - even though the load is done, we still want to play out the last 20 frames of animation before we run off to the next scene. The workaround is clearly not going to help us in that respect because the loader has no idea what's going on with the animation - and what's more, if you've got the loader calling the shots, you can't ever re-use it in another project without reworking a bunch of that code.

The Hard Way

We need passive alerting, and that means Events. So let's scratch the parent.someFunction line and dispatch a custom event instead:

  1. import flash.display.Sprite;
  2. import flash.events.Event;
  3.  
  4. public class ChildClass extends Sprite{
  5.  
  6. // ...
  7. // MainClass(parent).someFunction();
  8.  
  9. var e:Event = new Event('readyToGo');
  10. dispatchEvent(e);

Ok, that looks pretty good. Now whenever the child class needs to do something, it just shouts out that it's ready and anyone else can listen to it and act (or ignore) accordingly. What's more, we've eliminated a targetted call so now the child class will work inside any parent class (not just those with someFunction() defined).

Now, the parent has to listen to the child and take over the responsibility of acting when that event is fired.

  1. import flash.display.Sprite;
  2. import ChildClass;
  3.  
  4. public class MainClass extends Sprite{
  5.  
  6. // ...
  7. var c:ChildClass = new ChildClass();
  8. c.addEventListener('readyToGo', someFunction);

Perfect - now things are working as intended and there's no breach of OOP responsibilities!

⇠ AS2 to AS3: Calling a Method of a .parent Class (1 of 2)

I haven't posted in ages so I'm throwing out a quickie to get myself back in the rhythm. I don't have anything super-cool today so I'm going to kick off a series of posts for users who are jumping from AS2 to AS3. Mostly these will just be answers to super-common questions out on the forums so I can stop re-typing them all the time.

I see some version of this question posted almost daily: "I'm new to AS3 and I have a parent class and a child class; how can I call a function in the parent class from inside the child?"

By this time you've already tried parent.someFunction() and gotten this

Error 1061: Call to a possibly undefined method someFunction through a reference with static type flash.display:DisplayObjectContainer.

The problem is that the child class is essentially deaf and blind - it has no way of knowing what kind of object the parent is (it could be a Sprite, MC, stage, custom class, whatever) so Flash has to be safe and restrict you to the common denominator, DisplayObjectContainer, from which all those other classes derive. Because of that, the .parent property will only allow you to call DisplayObjectContainer methods on it such as removeChild, getChildByName, mouseEnabled, &c.

So right here there is a fork in the road – you can make a couple of assumptions and get a quick and easy answer and be done, or you can do a little reworking of your code and get to the bottom of the problem once and for all.

The Easy Way

Since most custom classes extend MovieClip, we can tell the compiler to go ahead and open up that functionality to us by treating .parent as a MovieClip instead of just a DisplayObjectContainer:

  1. MovieClip(parent).someFunction();

That line tells Flash that the parent is a MovieClip (or some offshoot) and therefore is a dymamic class – meaning you can add properties and public functions to it on the fly – so you can call anything you want on it and the compiler will search for it instead of falling back to what is explicitly stated in the class at compile-time.

If that's a no-go for you (say your parent is a Sprite, for example), you can still use this trick but you'll need to target the functionality of the main class a little more specifically.

  1. import flash.display.Sprite;
  2. import MainClass;
  3.  
  4. public class ChildClass extends Sprite{
  5.  
  6. // ...
  7. MainClass(parent).someFunction();

The Hard Way

Ok - judge me if you want but I've already spent way too much time on the first half of this post and I'm not even to the good stuff yet. I'm going to hammer out the second half of this and post it a little bit later so that this whole concept is more digestible. Continuation is imminent!

continued: AS2 to AS3: Calling a Method of a .parent Class (2 of 2) ⇢