Search code examples
actionscript-3

moving multiple symbols across stage as3


I am working on a simple video game in which I need to move 50+ symbols across the stage with the same speed. I would like to use a single as3 command with which I can target all symbols at the same time. Currently I have added the symbols one by one:

Code snippets for moving symbols to the right:

stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_SetKeyPressed_3);
stage.addEventListener(KeyboardEvent.KEY_UP, fl_UnsetKeyPressed_3);

 function fl_MoveInDirectionOfKey_3(event:Event)
{
    if  (rightPressed) {
        mc1.x = 5;
        mc2.x = 5;
        mc3.x = 5;
        mc4.x = 5; 
        and so on....,
}

What can I do to apply the function to all mc symbols in one go?

Thank you!


Solution

  • Loops. When you need to address multiple objects in the same manner, you use loops. Loop is the way to perform the same course of actions on any (literally any) given number of objects, be it 2, or 10, or 100, or 1000000.

    First of all, you need a way to address all the objects you are going to work with. When you say 'loop' you mostly keep 'array' or 'list' in mind. Loops and arrays get along very well.

    The most straightforward way is to create an Array with all the items:

    var A:Array = [mc1, mc2, mc3, /* and so on */ , mc50];
    

    However, there's no beauty in it, and also if you suddenly want to increase the number of these objects from 50 to 150, you will have a lot of tedious work to do.

    Luckily, your clips are named handily, so you can access by constructing their names and then through method getChildByName(...);

    // Define an empty Array.
    var A:Array = new Array;
    
    // A temporary variable to hold a name of the clip.
    var aName:String;
    
    // A temporary variable to refer your multiple clips one by one.
    var anObject:DisplayObject;
    
    // This loop performs 50 times with i bearing the value of
    // 1, 2, 3 and so forth to 50 each separate time.
    for (var i:int = 1; i <= 50; i++)
    {
        // Construct a clip name from letters "mc" and the
        // text representation of i, so it first constructs "mc1"
        // then "mc2" then "mc3" and so forth up to "mc50".
        aName = "mc" + i;
    
        // This operation finds an object with the given instance name.
        anObject = getChildByName(aName);
    
        // Put the found object into the Array.
        A.push(anObject);
    }
    

    Now if you want to go up from 50 to 150 you just change i <= 50 to i <= 150 and that's it.

    So, what if these clips indeed name with "mc" and some number, but you are not sure the numbers are thorough from 1 to 50 without any gaps? Say, there's no "mc3"? The script above will form Array with null entries in it: [mc1, mc2, null, mc4, mc5, ... , mc50]. Not good. Still, there's another way to go.

    // Define an empty Array.
    var A:Array = new Array;
    
    // A temporary variable to hold a name of the clip.
    var aName:String;
    
    // A temporary variable to check if name is right.
    var anIndex:int;
    
    // A temporary variable to refer your multiple clips one by one.
    var anObject:DisplayObject;
    
    // This loop iterates i over the number of display children
    // in the current display container. It is to get each child
    // with no regard of its name and to process it.
    for (var i:int = 0; i < numChildren; i++)
    {
        // This operation gets a child by its z-index.
        anObject = getChildAt(i);
    
        // Now we should figure if that child has a name that
        // falls into "mc" + some number schema.
    
        // Extract a portion of name from 2-nd character and on.
        aName = aChild.name.substr(2);
    
        // Convert it to the integer value.
        anIndex = int(aName);
    
        // Construct a proper name.
        aName = "mc" + anIndex;
    
        // This check will pass for names like "mc1" or "mc50"
        // but will fail for "mcx10", for example.
        if (aChild.name == aName)
        {
            // Put the found object into the Array.
            A.push(anObject);
        }
    }
    

    This one will forgive you if you omit any numbers while numbering your clips, and also does not require of you to actually count them. The downside: it is a bit long, and still requires to give these clips proper instance names.

    There's a better way, yet.

    If all these clips are instances of the same Library object, or maybe of a limited number of Library objects, you can assign them class names (the example below explains it with 2 classes: MCNumA and MCNumB, also keep in mind that class names are case-sensitive) and check the classes instead of instance names. The upside: you don't have to thoroughly name 50+ objects.

    import MCNumA;
    import MCNumB;
    
    // Define an empty Array.
    var A:Array = new Array;
    
    // Define a list of classes these objects belong to.
    var classList:Array = [MCNumA, MCNumB];
    
    // A temporary variable to iterate through class list.
    var aClass:Class;
    
    // A temporary variable to refer your multiple clips one by one.
    var anObject:DisplayObject;
    
    // This loop iterates i over the number of display children
    // in the current display container. It is to get each child
    // with no regard of its name and to process it.
    for (var i:int = 0; i < numChildren; i++)
    {
        // This operation gets a child by its z-index.
        anObject = getChildAt(i);
    
        // Iterate, get each class into aClass variable.
        for each (aClass in classList)
        {
            // Check, if this child belongs to any of the classes.
            if (anObject is aClass)
            {
                // Put the object into the Array.
                A.push(anObject);
    
                // Stop checking classes, we've found one already.
                // This breaks out of the inmost loop ("for each" one).
                break;
            }
        }
    }
    

    Now, one way or another, we have an Array of the objects you want to affect. The rest is pretty simple.

    // Somewhere in your script.
    if  (rightPressed)
    {
        // When you have a list of them, it is THAT simple!
        // Iterate over all objects in A.
        for each (anObject in A)
        {
            // Give each object a proper X-coordinate.
            anObject.x = 5;
        }
    

    If you need to access less basic functionality, that exceeds the capabilities of DisplayObject class, you need to specify (for FlashPlayer) which class these objects actually belong to. It is called "type casting":

    // Iterate over all objects in A.
    for each (anObject in A)
    {
        // Type casting. It will elevate the object's class
        // if it is really a MovieClip, or will return null.
        var aClip:MovieClip = anObject as MovieClip;
    
        // This check will return true if reference is not null.
        if (aClip)
        {
            // Stop the actual MovieClips.
            aClip.stop();
        }
    }
    

    If you are 100% sure all of them are MovieClip's, you are free to omit the check and iterate with the correctly typed variable:

    // A temporary variable to iterate all the MovieClips.
    var aClip:MovieClip;
    
    // Iterate over all objects in A as MovieClips.
    for each (aClip in A)
    {
        // Stop the MovieClips.
        aClip.stop();
    }