arraysactionscript-3movieclip

Why is AS3 creating new instances in for loop?


Strangest behavior I have seen from actionscript so far and I have been working with AS for over 10 years.

var clip1:MovieCip = new MovieClip();  
var clip2:MovieCip = new MovieClip();  
var clip3:MovieCip = new MovieClip();    
var clip;

var myarray:Array = new Array(clip1, clip2, clip3);    

for each (clip in myarray)
{ removeChild(clip);
  clip = new mc();
  trace(clip.name); }

seems simple enough right? well for some reason flash is changing the instance names to instanceX where X is some randomly assigned number and I am no longer able to call on the clips by their assigned names, for example if I try...

 clip1.x = 300;

flash will not throw an error but clip1.x does not move to 300. I have been working on this for a few hours, it seems the movieclips actually still exist but flash has created new movieclips! Please help


Solution

  • It seems you don't understand the difference between member names and instance names. I assume that you write code on the timeline, that means you operate inside the MovieClip object that is represented by that timeline (might be the main timeline, in this case you are operating inside the root).

    Member is an OOP word that represents fields (plain data and object references) and methods (bound functions) of the object. You can use dot notation or square bracket notation to access the members:

    this['a'] = 10;
    trace(this.a); // output: 10
    

    When you are writing code on timeline, when you declare variables or functions, you are actually declaring fields and methods (respectively) of the current MovieClip:

    var a:int = 10;
    
    trace(a);         // output: 10
    trace(this.a);    // output: 10
    trace(this['a']); // output: 10
    

    Keep in mind that variables, declared inside function bodies, are not object members but the local function variables:

    function A():void
    {
        var a:int = 999;
    
        trace(a);      // output: 999
        trace(this.a); // output: undefined
    }
    

    Instance names are class members of DisplayObject class under a "name" name.

    trace(name);         // output: instance123
    trace(this.name);    // output: instance123
    trace(this['name']); // output: instance123
    

    The confusing part about it is that Flash auto-declares pre-designed things as the object members with the member names same as instance names. So, if you put some MovieClip with the instance name MC1, you can address it as following:

    trace(MC1);         // output: [object MovieCip]
    trace(this.MC1);    // output: [object MovieCip]
    trace(this['MC1']); // output: [object MovieCip]
    trace(getChildByName("MC1"));      // output: [object MovieCip]
    trace(this.getChildByName("MC1")); // output: [object MovieCip]
    

    You can turn the auto-declare option off at File > Publish Settings > AS3 Setings > Auto-declare Stage Instances. If you do so, the output will be different:

    trace(MC1);         // output: undefined
    trace(this.MC1);    // output: undefined
    trace(this['MC1']); // output: undefined
    trace(getChildByName("MC1"));      // output: [object MovieCip]
    trace(this.getChildByName("MC1")); // output: [object MovieCip]
    

    Also, that auto-declare thing works, let me stress it again, only with pre-designed content. If you create new instances of anything and addChild(...) them to the container, it won't automatically add their references as the container OOP members.

    Then, how it affects your problem.

    You call clip1.x = 300; and there's no error. Of course there are none. The clip1 member still holds the reference to the originally declared and instantiated var clip1:MovieCip = new MovieClip(); and you never reassigned anything to this member. So you address the valid MovieClip that is not attached to anything, but that does not matter to AS3 or Flash platform: you are performing a valid operation on valid object.

    If you want to address the newly created instances, you should do it via the array you put them to, or via carefully organized instance names, or by assigning their references to the members of respective member names:

    var clip0:MovieCip = new MovieClip;
    var clip1:MovieCip = new MovieClip;
    var clip2:MovieCip = new MovieClip;
    var clip3:MovieCip = new MovieClip;
    
    var myarray:Array = new Array(clip0, clip1, clip2, clip3);
    
    for (var i:int = 0; i < myarray.length; i++)
    {
        // You better call the class MC, because lowercase
        // class name looks like a variable name.
        var aClip:MC = new MC;
    
        // Give it a proper instance name.
        aClip.name = "clip" + i;
    
        // Assign it as a member of current object.
        this["clip" + i] = aClip;
    
        // Put it to designated place into the Array.
        myarray[i] = aClip;
    }
    

    Now you can address it any way you want:

    trace(clip1);         // output: [object MC]
    trace(this.clip1);    // output: [object MC]
    trace(this['clip1']); // output: [object MC]
    trace(myarray[1]);    // output: [object MC]
    trace(getChildByName("clip1"));      // output: [object MC]
    trace(this.getChildByName("clip1")); // output: [object MC]