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();

23 Responses to “AS2 to AS3: Dynamic instance names”

  1. Paul Trani Says:

    Thanks so much for this Rob. This is an absolute HUGE help to me! Thanks so much and keep up the great work!

  2. Eric Says:

    Thank you so much! This is one of those stupid AS3 things that I just could not wrap my head around, even after working through several projects and class based OOP, etc

  3. Ben Garney Says:

    What about using a Dictionary?

  4. Dangerously Says:

    Hey,

    Thanks for the info. This is just what I was looking for. Now I just wish that I had thought searching for this sooner, I just wasted several hours trying to get ‘.name’ to work!

  5. jim Says:

    isn’t it handier to use clips.push(mc) instead of clips[i] = mc in the loop?

  6. Rob Says:

    Jim – that’s a great point. I used the bracket notation here to show the index number going in and being preserved later; if you wanted to optimize further you could drop the .name tag completely (if you aren’t using it for anything) and try a faster loop style.

  7. Angel Romero Says:

    Man, I was about to try this but wanted to see if anybody else attempted it first. I am glad to see that it logically works. Thanks for the example!

    I have got to let others know. This has been a problem in numerous forums.

  8. Joe Says:

    I commonly use systems where attributes are added dynamically to objects. I fact, the application doesn’t even know what the attribute is called in advance, because even that is dynamic.

    Things like:

    this['mc3'].play();

    Can in fact work, since dynamic objects work in a dictionary like way. I’m sure it isn’t “proper” in some peoples mind, but done right it can work well.

    Stuff like this in loops can be useful.

    propertyName = “mc” + i;
    mc = new MovieClip();
    this['propertyName'] = mc;
    addChild(mc);

    (I don’t known if this exact code works, but I do similar stuff often.)

  9. David Darke Says:

    Perfect!!!! Very clear and concise !!!

  10. ookla Says:

    finally! thanks!

  11. pollen Says:

    hi there,

    I’m running into exactly the same problem but within a class.
    Basically I need to set a new id each time an instance of that class is created so I can use it later in the resetMenu function.

    the .gs is GreenSock tweening classes.

    ANY IDEAS ARE WELCOME!
    Thanks.

    Below is the .as code:

    package{
    import flash.display.*;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import gs.*;

    public class customBtn1 extends MovieClip {

    //*************************
    // Properties:
    public var xPos:uint;
    public var yPos:uint;

    public var btnId:int;
    private var totalButtons:int = 5;
    private var i:uint = 0;
    public var counter:uint;

    private var myBtn:MovieClip;
    private var btnNames:Array = [];

    private var target:MovieClip;
    private var theName:String;

    //*************************
    // Constructor:
    public function customBtn1(i) {
    myBtn = this;
    //trace(myBtn);
    myBtn.name = ‘btn’ + i;

    btnNames[i] = myBtn.name;
    trace(‘BBB= ‘ + myBtn.name);
    trace(btnNames[i]);

    init();
    }

    private function init():void {
    buttonMode = true;
    addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
    addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);

    addEventListener(MouseEvent.CLICK, clickHandler);
    }

    private function getBtnId():void{
    trace(‘name= ‘ + name);
    if(name.length==4){
    btnId = int(name.charAt(3));
    //trace(‘btnId= ‘ + btnId);
    }else{
    btnId = int(name.substring(3,5));
    //trace(‘btnId= ‘ + btnId);
    }
    }

    private function resetMenu(target):void{
    trace(‘///////////////// at Reset Menu’);
    //trace(‘btnId= ‘ + btnId);
    trace(‘target >>>>>= ‘ + target);
    for(i=0;i<totalButtons;i++){

    if(i==btnId){
    trace(‘PPP ‘ + i +’ = ‘+ btnNames[i]);
    //trace(‘i IS EQUAL TO btnID’);
    target.removeEventListener(MouseEvent.MOUSE_OUT,mouseOutHandler);
    }else{ //trace(‘i IS NOT EQUAL TO btnID’); trace(‘PPP ‘ + i +’ = ‘+ btnNames[i]); //TweenLite.to(theMov, .5, {tint:0×999999}); //btnNames[i].mouseEnabled = true;
    }
    }//END LOOP
    }

    public function setPosition(xPos:uint,yPos:uint) {
    this.x = xPos;
    this.y = yPos;
    }

    private function mouseOverHandler(event:MouseEvent):void {
    TweenLite.to(event.target, .5, {tint:0xff0000});
    }

    private function mouseOutHandler(event:MouseEvent):void {
    TweenLite.to(event.target, .5, {tint:0×999999});
    }

    private function clickHandler(event:MouseEvent):void {
    event.target.mouseEnabled = false;
    getBtnId();
    resetMenu(event.target);
    }
    }
    }

    And in the .fla:
    var totalButtons:uint = 5;
    var i:uint;
    var spacing:uint=70;

    for (i = 0; i < totalButtons; i++){
    var myBtn:customBtn1= new customBtn1(‘btn’ + i);

    myBtn.setPosition((spacing * i) + 30,50);
    this.addChild(myBtn);
    }

  12. Watashiii Says:

    I love you and I want to have your babies

  13. Tony Says:

    Lovely. Thank you. Been banging my head on this one for a while.

  14. Larry Says:

    So using this method “clips[3].play();”, how would you attach an event listener to clips[3]?

  15. saintist Says:

    very nice! you save my time, thanks

  16. Novian Says:

    Hey Larry,

    This is a little after the fact but I believe you just add your event listener to the mc when you generate your array e.g. mc.addEventListener(MouseEvent.CLICK, eventHandler)

    I hope this helps you are someone else.

    Novian

  17. arctelix Says:

    This shold be the cover page for every Action Script 3.0 manual!! Would have saved me countless hours.

  18. Ronak Says:

    THANK U VRY MUCH………

  19. fedoo Says:

    Hi, thanks for this, I was desperate before I discover this site. You helped me a lot.

    But I think I have better solution:

    Let’s say we want to add multiple instances of one object from library (for example some points/movieclip) and we then want to click on them and we also want from Flash to know which instances we clicked.

    We can work with names and strings but it is difficult and no effective. The idea with array is great but we don’t need make new variable for instance. It is easier to do something like this:

    var i:uint = 0;
    var points:Array = []; //array of future points

    and then when we add Movieclip on stage we use something like this:

    points[i] = new Movieclip();
    i++;

    each instance is stored in one element of array so we can call it through index of array.

    For examle. if we have some Mouse.CLICK listener we can write inside the function of listener:

    points[points.indexOf(event.target)];

    Now we know exactly on which instance we clicked.

    Hope it is undersandable. :)

  20. Hawk Says:

    Hi, I am trying to get an instance name of a sprite I created with code so I could move it with arrow keys but, it’s not working. Could you tell me how to fix it/what title to use so i can move my sprite? Thanks.

    Code:
    import flash.events.*;
    var size:int=50;
    // size of the object

    stage.addEventListener(Event.ENTER_FRAME,CreateObjectListener);
    function CreateObjectListener(event:Event):void {
    var objects:Array=[];
    for (var i = 0; i < 5; i++) {
    var object:Sprite = new Sprite();
    object.name="object"+i;
    addChild(object);
    object.x=275;
    object.y=200;
    objects[i]=object;
    }
    with (object.graphics) {
    lineStyle(1, 0×000000, 1);
    beginFill(0xFF0000, 1);
    moveTo(-size/5,-size);
    lineTo(size/1,-size);
    lineTo(size/1,size);
    lineTo(-size/1,size);
    lineTo(-size/1,-size);
    }
    }

  21. john pap Says:

    Respect

  22. Ignacio Says:

    wuauuuuuuu!!!

    te amo!!!!

    Muchas gracias!!!

    3 dias buscando!

    desde Antofagasta Chile. !!! Te amo!!!!!

  23. getChildAt(0).addChild(my_loader) ? - Flashforum Says:

    [...] zwischen Instanzname und Name Eigenschaft so nicht ganz klar. Geholfen hat mir dieses Tut: Calypso88 Blog Archive AS2 to AS3: Dynamic instance names. Ich komme trotzdem noch nicht ganz weiter. Es tun sich mir da mehrere Fragen auf. Wenn ich so [...]

Leave a Reply