Nested Loops

Loops provide a great way of automating a set of scripting tasks. However, loops can accomplish more than the repetitive execution of a set of actions. A nested loopthat is, a loop placed inside another loopcan be useful for creating a looping sequence that executes a set of actions, changes a bit, executes those same actions again, changes a bit, and so on. Here's an example of a nested loop:


var i:Number = 0;

while (++i <= 10) {

  var j:Number = 0;

  while (++j <= 10) {

    // perform these actions

  }

}


The actions in the loops will be executed 100 times. Here's the underlying logic: the outer loop (which uses i) is set to loop 10 times. With each iteration of this outer loop, two things occur: the variable j is reset to 0, which then enables the inner loop (which uses j) to loop 10 times itself. In other words, on the first iteration of the outer loop, the inner loop will loop 10 times; on the second iteration, the inner loop will again loop 10 times; and so on.

graphics/09inf08.gif

Nested loops are great for breaking repetitive tasks into a hierarchical process. To help you understand this concept, think about writing a letter. A letter represents a nested-loop process in which you start on line 1 and write perhaps 100 characters, drop to line to 2 and write 100 characters, and so on. If your letter is 25 lines long, a script to do the work might look something like this:


var i:Number = 0;

while (++i <= 25) {

  var j:Number = 0;

  while (++j <= 100) {

    // type a character

  }

  // drop down to the next line

}


Keep in mind that you aren't restricted to nesting just one loop inside another; you can use as many loops within loops as your project requires.

In the following exercise, you use nested loops to create a grid of images that appear when an item in the drop-down list is selected.

  1. Open pictureShow2.fla.

    On the top of the stage are three movie clip instances: pictures1_mc, pictures2_mc, and pictures3_mc. In this exercise, you duplicate one of these three movie clips (depending on which item in the drop-down list is selected) to form a grid of images onscreen.

  2. With the Actions panel open, select Frame 1 in the Actions layer and add this function after the current script on that frame:

    
    function itemClicked(pictureID:Number) {
    
      var picToDuplicate:String = "pictures" + pictureID + "_mc";
    
      var xSpacing:Number = 160;
    
      var ySpacing:Number = 120;
    
      var xStart:Number = 190;
    
      var yStart:Number = 30;
    
    }
    
    

    The preceding exercise set up the duplicated list_btn button instances to call this function and pass it a parameter value (pictureID) when clicked. When it's finished, this function will copy one of the three pictureID movie clip instances at the top of the stage four times, forming a two-by-two grid, and then send each duplicated instance to a unique frame to display an image.

    graphics/09inf09.gif

    The first line in this function creates a variable called picToDuplicate. This variable's valuewhich is based on the pictureID value of 1, 2, or 3 that was passed to the function when it was calledis then set to picture1_mc, picture2_mc, or picture3_mc, which happen to be the names of the instances containing pictures on the stage. We'll use this value later in this function definition to identify which instance to duplicate.

    The xSpacing variable represents the amount of space to allot between the left sides of the two movie clip instances found on the same horizontal row. The ySpacing variable indicates the space between two movie clips in the same column. The values of these spacing variables are arbitrary and will depend largely on the amount of space you like between movie clips.

    The next two variables, xStart and yStart, represent the starting position of the first duplicated movie clip in relation to the stage. Any subsequent movie clip duplicates are positioned relative to this point.

  3. Add this script at the bottom of the itemClicked() function definition:

    
    var v:Number = 0;
    
    var i:Number = -1;
    
    while (++i < 2) {
    
      var j:Number = -1;
    
      while (++j < 2) {
    
        ++v;
    
        var name:String = "pictures" + v;
    
        _root[picToDuplicate].duplicateMovieClip(name, v);
    
        _root[name]._x = xStart + i * xSpacing;
    
        _root[name]._y = yStart + j * ySpacing;
    
        _root[name].gotoAndStop(v);
    
      }
    
    }
    
    

    This loop contains a nested loopthe portion of the function that actually creates the two-by-two grid of movie clip instances. A single loop would create a single column of movie clip instances. In contrast, a nested loop creates two instances in a column, alters the script slightly to "move" the column coordinates, and creates another two instances in a column (which we'll explain in a moment). Let's look at the logic that allows it to work.

    The outer loop, beginning at line 3 of the script, increments i by 1 (++i), setting an initial value of 0. The condition of this outer loop says, "As long as i is less than 2, execute the actions below." Because 0 < 2, the actions within the loop are executed. The first action sets the value of j to -1. Then a nested (inner) loop appears that uses the value of j. First, j is incremented by 1 (++j) and a condition is set that says, "As long as j is less than 2, continue looping through the actions that follow."

    The script continues to do nothing but execute the actions in this inner loop until that condition becomes false. During the first iteration of this inner loop, the value of v is incremented by 1 (++v), giving it a value of 1. This variable's value is used several times in the lines of script that follow. Using ActionScript that should be familiar to you by now, the appropriate pictureID movie clip instance is duplicated and positioned. During the second iteration of this inner loop, the value of j is incremented by 1 (as shown in the loop's conditional statement), giving it a value of 1, which is still less than 2, so the actions within that loop are executed again.

    This inner loop cannot perform a third iteration because j would be incremented again (++j), making it equal to 2 (a condition that exits the inner loop). As a result, the script revisits the outer loop. At that point, i (used by the outer loop) is incremented by 1 (++i), giving it a value of 1, which is still less than 2, so the actions in the outer loop are executed again. As a result, the value of j is reset to -1, and the actions in the inner loop are executed two more times.

    The concept just described can be tricky; review the logic until you understand it thoroughly.

    graphics/09inf10.gif

    To achieve the effect of creating a two-by-two grid of movie clips (the proper spacing), you use this script:

    
    _root[name]._x = xStart + i * xSpacing;
    
    _root[name]._y = yStart + j * ySpacing;
    
    

    The first line uses the current value of i to set the horizontal spacing. The second line uses the current value of j to set the vertical spacing when a movie clip is duplicated. You've already learned that with each outer loop iteration the inner loop performs two iterations. While i has a value of 0, the value of j is set to both 0 and 1 during execution of the inner loop, i is incremented to a value of 1, and the value of j is set to both 0 and 1. Because we know the values of xStart, xSpacing, yStart, and ySpacing, as well as how the values of i and j are incremented in the looping process, we can determine the spacing for each clip.

    First instance duplicated:

    
    _x = 190 + 0 * 160;// x set to 190
    
    _y = 30 + 0 * 120;// y set to 30
    
    

    NOTE

    Remember that in a mathematical expression, multiplication always occurs before addition.

    Second instance duplicated:

    
    _x = 190 + 0 * 160;// x set to 190
    
    _y = 30 + 1 * 120;// y set to 150
    
    

    Third instance duplicated:

    
    _x = 190 + 1 * 160;// x set to 350
    
    _y = 30 + 0 * 120;// y set to 30
    
    

    Fourth instance duplicated:

    
    _x = 190 + 1 * 160;// x set to 350
    
    _y = 30 + 1 * 120;// y set to 150
    
    

    graphics/09inf11.gif

  4. Add this action as the last line in the itemClicked() function definition:

    
    removeButtons();
    
    

    graphics/09inf12.gif

    This action calls a function named removeButtons(), which will remove the buttons in the drop-down list after a button has been clicked and the picture grid created. Let's create the function.

  5. Add this code at end of the frame on the Actions layer:

    
    function removeButtons() {
    
      var numberOfButtons:Number = buttonNames.length;
    
      var i:Number = -1;
    
      while (++i<numberOfButtons) {
    
        var name:String = "item" + i;
    
        dropDownList_mc[name].removeMovieClip();
    
      }
    
    }
    
    

    This function uses a simple while loop to loop through and remove all the buttons (which are actually the duplicate movie clip instances item0, item1, and item2) that make up the drop-down list choices under the Menu button. This loop works in similar fashion to the loop we used to create the duplicates that make up the list. Let's analyze this loop's syntax.

    The value of numberOfButtons, which was also used in the populateList() function, is based on the length property of the buttonNames array. Because that array has three elements, the loop will perform three iterations. On each loop, the variable name is set based on the current value of i. The removeMovieClip() method is then used to remove the duplicate movie-clip instances referenced by the current value of name, thus removing the list of choices beneath the Menu button.

  6. Choose Control > Test Movie to test your work.

    Click the Menu button to display the list of choices. As you click any of the list buttons, the grid of images is created based on the value of pictureID that's passed to the itemClicked() function. Notice that the removeButtons() function removes the list choices.

  7. Close the test movie and save your work as pictureShow3.fla.

    In this exercise, you used nested loops to create a grid of images onscreen. While you could have dragged and placed four movie clip instances on the stage to accomplish the same goal, you used a nested loop to automate the entire process in such a way that, with a couple of minor adjustments, the script can create a grid of any sizeperhaps as large as 100 by 100 images. Using loopsespecially nested loopsin this fashion not only helps you to automate processes that you might otherwise perform manually in the authoring environment; it also enables your projects to scale up or down dynamically based on conditions that exist while the project plays.