15. Creating Groups of Objects and Repeating Actions Using Loops

In all the examples so far, you have been working with individual instances of objects. As you work with more complex projects that have multiple instances of objects, it can quickly become unworkable without some way to access properties or values with each instance in a logical group. For example, if you have a project with a couple instances of a Library object, it is pretty manageable. But what about when you have a dozen? A hundred? Or even a thousand? There needs to be some way to organize these into groups to make it easier for you as a coder to work with them.

In this chapter, you’ll get an introduction to grouping objects into named sets called arrays. In addition, you’ll look at how to use loops to execute blocks of code a repeated number of times based on a conditional test using the for loop.

What Are Loops?

A loop is a method in ActionScript to mark a block of code that will repeat a number of times based on a condition. The premise is that the loop of code will repeat continuously as long as the condition of the loop, defined by a Boolean conditional test, remains true.

Loops are used for a wide variety of functions. There are situations where you want to repeat the same action more than once, potentially thousands of times, and loops provide a concise and adjustable way to repeat code.

You can also use loops to go through groups or sets of objects called arrays. You’ll learn about arrays in more detail in the second half of the chapter.

The most common loop you will encounter will ask for the test of a condition, and if that condition is true, run the block of code in the body of the loop, and then retest the condition, resulting in a cycle. If the condition proves to be false at some point, the loop stops executing. This is the basic premise of the for loop.

Using the for Loop

The for loop is the most basic of the loop types, and undoubtedly will be the one you will work with the most. As mentioned earlier, the basic architecture of a for loop starts with a Boolean conditional test. If the test is true, the loop executes. When the code of the loop is finished, it then retests the condition. If the condition is still true, the loop runs again. If the condition is false, the loop stops and continues to run the rest of the code.

Let’s take a look at an example of a for loop and break down the parts using the callouts in Figure 15.1.

Figure 15.1. A simple for loop

image

When you create a for loop, you start with the for statemen image. After the opening statement, you create a pair of parentheses that contain three sections, each separated by a semicolon.

The first statement image defines a special variable used in a loop called an iterator. An iterator is a variable inside of a loop that defines how many times the loop will run. Typically, the iterator has the name of i, but you can use whatever variable name you want. You need to define the iterator to have a value to test against within the loop. Using the var statement, this loop creates the variable i, and sets it to a new object type, the uint type. This is a variation of the Number type. uint stands for unsigned integer, which states that the value will not contain decimals (also called an integer), and will only be positive (meaning that it can’t have a negative or positive “sign” thus “unsigned”).

The next section image contains the conditional test itself. This is just like the conditional tests you have looked at before. In this case, you are asking to test if the variable i is less than the number 10.

For the conditional to test different situations, you need to change the iterator variable in some way. The final section image is the step of the loop. The step defines how you modify the iterator at the end of a loop execution, but before the condition is retested and the loop runs again. If you didn’t change the iterator in some way, you could potentially have a condition called an infinite loop that will run forever, because the testing condition will never become false. Infinite loops slow down your system, and eventually you’ll be asked to kill or close your application.

Finally, you’ll create a code block using braces that encapsulate the lines of code that will run with each iteration of the loop image.

Let’s use this example in a Document class and see exactly how it works. Here is the Document class for the loop:

package  {
    import flash.display.MovieClip;
    public class Loops extends MovieClip {
        public function Loops() {
            for (var i:uint = 0; i < 10; i++)
            {
                trace(i);
            }
        }
    }
}

When this project runs, you’ll get the messages displayed in Figure 15.2.

Figure 15.2. Output panel from the loop

image

Let’s step through this a few times and see exactly what takes place. First, you start the loop with the for statement and create an iterator variable that begins with the value 0. You test the condition: Is 0 less than 10? The answer is true, so you run the loop.

The loop code sends the current value of the iterator variable to the Output panel. The loop code is then finished.

The loop processes the step, which increments the iterator by 1, resulting in 1. The loop starts again, retesting the condition, running the code, and sending the value of the iterator to the Output panel.

The iterator eventually equals 9, displays in the Output panel, and then increments by 1, resulting in 10. You retest the condition: Is 10 less than 10? No, it isn’t—it is equal, so the result is false. Since the conditional test failed, the loop ends, and the program finishes.

Using this basic model, you can create loops that will run a known number of times (as in the example), or test against a variable that could run a different number of times based on different conditions.

For example, if you wanted to have a specific action, like a calculation, change multiple times, you would use a loop to do this. Later in the chapter, you’ll learn about arrays, which are groups of objects you can use to repeat the same action over each object in the group. For example, if you wanted to change the location of several MovieClips, you could put them in a group, and using the loop, move through all the objects within the group and run the same piece of code to change the location.

Controlling the Flow of Loops with break and continue

You might have situations where you want to alter the flow of a loop. Using the break and continue statements, you can suspend execution of code in the loop body, or end the loop early.

The break statement exits out of the loop immediately, regardless of the result of your loop conditional test. Use this whenever you want to exit a loop. The continue statement suspends the execution of the loop code body, applies the step to the iterator, and restarts the loop again.

Here is an updated example that uses the break and continue statements in conjunction with a couple if statements:

package  {
    import flash.display.MovieClip;
    public class Loops extends MovieClip {
        public function Loops() {
            for (var i:uint = 0; i < 10; i++)
            {
                if (i == 5) continue;
                if (i == 7) break;
                trace(i);
            }
        }
    }
}

In this example, if the iterator is equal to 5, you are skipping the rest of the loop code using the continue statement. When the iterator equals 7, you will exit out of the loop entirely using break, even though the loop condition is still true.

Notice that you have the break and continue statements on the same line as the if statement. Because you are running only a single command for the conditional, you can omit the braces and put everything on the same line.

Figure 15.3 shows the result when you run this new code.

Figure 15.3. Using break and continue to alter the flow of a loop

image

As you can see, the code never outputs the number 5, because you are skipping that part of the loop body using the continue statement. You also never get any numbers greater than 7 because you exit out of the loop using break.

Nesting Loops

It is possible to nest loops inside of each other. In nested loops, the inner loop runs a set number of times for each execution of the outer loop. Here is an example:

package  {
    import flash.display.MovieClip;
    public class NestedLoops extends MovieClip {
        public function NestedLoops() {
            _init();
        }
        private function _init():void
        {
            for (var i:uint = 0; i < 3; i++)
            {
                trace ("Outer loop #" + i);
                for (var ii:uint = 0; ii < 3; ii++)
                {
                    trace ("Inner loop #" + ii);
                }
            }
        }
    }
}

This code creates the following in the Output panel:

Outer loop #0
Inner loop #0
Inner loop #1
Inner loop #2
Outer loop #1
Inner loop #0
Inner loop #1
Inner loop #2
Outer loop #2
Inner loop #0
Inner loop #1
Inner loop #2

The outer loop starts, with the iterator at 0, then runs the inner loop three times before it goes back and reruns the outer loop.

When you work with nested loops, make sure that you are working with the right iterator variables. As you can see in this example, unique iterator variable names are used for each nested loop. This is required, otherwise your inner loop, will change the iterator of the outer loop. Also, inner loops must be completely self-contained, meaning they are completely within the code block’s curly brackets of the outer loop. If they aren’t they won’t work correctly.

Another Style of Loops, the do Loop

When using the for loop, there is a chance that the code within the loop will never run. If the conditional results in false at the start of the first execution of the loop, the loop will be skipped entirely. If you have a loop that you want to run at least once, and then test the loop condition at the end, there is an option for you called the do loop, sometimes referred to as the do...while loop.

Another difference with the do loop is that it doesn’t have an iterator variable defined inside the loop, so if you are running something based on an existing variable, the do loop might be the right fit.

Here is a simple example using a do loop:

package  {
    import flash.display.MovieClip;
    public class DoLoop extends MovieClip {
        public function DoLoop() {
            var myValue:uint = 0;
            do
            {
                trace(myValue);
            } while (myValue != 0)
        }
    }
}

In this example, you use the do statement to start the body of the loop, which sends a statement to the Output panel. At the end, you use the while statement to cue up the conditional test that you want to use to determine if the loop runs again. If the condition is true, the loop runs again, testing the condition again at the end.

In this case though, the condition test will be false, even after the first time you run the loop; however, unlike the for loop, the loop will run at least once, even though the test will be false in the end.

Creating Groups of Items with Arrays

Often, you’ll have multiple objects in your application that you need to work with. Having a few or even hundreds of objects can be difficult to manage. ActionScript can make managing multiple objects easier by grouping objects into named groups called arrays.

Arrays are collections of objects that have a specific order. You can refer to any object within the collection and even loop through the objects in the array. Arrays can contain strings, numbers, or even MovieClips, which makes it perfect to house groups of objects that you are showing on the Stage.

Let’s start with a basic example using strings (the names of some of my current and past pets), and you can evolve it from there. This example is within a new Document class:

package  {
    import flash.display.MovieClip;
    public class SimpleArray extends MovieClip {
        public var myArray:Array;
        public function SimpleArray() {
            myArray = ["Binky", "Hoover", "BB", "Rocket"];
            trace(myArray);
        // "Binky", "Hoover", "BB", "Rocket"
            trace(myArray[0]);          // "Binky"
            trace(myArray.length);      // 4
        }
    }
}

Just like with any object in ActionScript, you need to create a named variable to refer to it. In this case, you are using the name myArray and are typing it as an Array.

To create the initial set of array items, you assign to the array a set of objects encapsulated in square brackets and separated by commas.

myArray = new Array("Binky", "Hoover", "BB", "Rocket");

You can send the entire array to the trace statement, which lists the items that are inside it.

In this array, you have four specific strings inside the collection. You now need a way to access the objects within the array. Each item that is contained in array is assigned a number, which is called its index. The index number is automatically assigned when you create an array. The index numbers start with 0 and each item then counts up from there.

Knowing that, the string “Binky” is element 0 of the myArray object. “Hoover” is element 1, “BB” is element 2, and finally, “Rocket” is element 3.

You can access the elements of the array using the index number. When you attach the square brackets to the end of the name of the array and include the index number (or an evaluation that will result in a number), you are able to point to that specific item in the array and work with it.

Using the statement myArray[0], you are able to access the 0 index, which is the string “Binky”, and then send that to the trace statement.

The final trace statement is accessing a property of the array. The length property returns the total number of elements that are in the array collection, which in this case is 4.

Modifying an Array

After you create an array, you’ll undoubtedly want to make changes to the contents at some point. If you use the assignment operator and use bracket notation, you’ll overwrite the existing contents of the array.

So, to make changes to existing items you can use the index element selector and assign a new value to it. Here is an example:

package  {
    import flash.display.MovieClip;
    public class SimpleArray extends MovieClip {
        public var myArray:Array;
        public function SimpleArray() {
            myArray = ["Binky", "Hoover", "BB", "Rocket"];
            trace(myArray[2]);
            myArray[2] = "Tilly";
            trace(myArray[2]);
        }
    }
}

The result will output:

BB
Tilly

In this example, you are accessing index 2 of the array and are overwriting its value using the assignment operator.

Now, this is fine if you need to change values to existing array items, but if you want to add items to the collection and make the collection larger, this won’t work. Luckily, there is a method of the Array class that you can use called push() that will add an item to the end of the array collection and give it a new index number.

Here is an example:

package  {
    import flash.display.MovieClip;
    public class SimpleArray extends MovieClip {
        public var myArray:Array;
        public function SimpleArray() {
            myArray = ["Binky", "Hoover", "BB", "Rocket"];
            trace(myArray);
            myArray.push("Tilly");
            trace(myArray);
        }
    }
}

When you run this example, you’ll get the following in the Output panel:

Binky,Hoover,BB,Rocket
Binky,Hoover,BB,Rocket,Tilly

The push() method accepts new items and adds them to the end of the collection. You can add multiple items in a single statement. Just separate them using commas within the push() method call.

That covers how to add items, but what about removing them? Interesting thing about removing items—when you remove an item, you will need to shift the index numbers of all of the other items. And guess what? There’s a method for that! The splice() method of the Array class allows you to select one or more items and remove them from the group. The array will then rearrange itself and renumber the remaining elements so there are no gaps in element IDs. The splice() method asks for the first element you want to remove, using the element’s index number, and then the number of items that you want to remove.

Below is an example:

package  {
    import flash.display.MovieClip;
    public class SimpleArray extends MovieClip {
        public var myArray:Array;
        public function SimpleArray() {
            myArray = ["Binky", "Hoover", "BB", "Tilly", "Rocket"];
            trace(myArray);
            myArray.splice(3,1);
            trace(myArray);
        }
    }
}

When you run this example, you’ll see the following in the Output panel:

Binky,Hoover,BB,Tilly,Rocket
Binky,Hoover,BB,Rocket

As you can see, you were able to remove Tilly from the group. (Poor Tilly!) You were able to do that using the splice() method and indicate you wanted to remove starting with the index 3 element, and you wanted to remove just one item. You could omit the second parameter if you wanted to remove everything after the indicated index.

Using Loops to Create Arrays

Now that you know how to create groups or collections of items, let’s look at a common case that you might come across. In this example, there is an object in the Library called BlueCircle that is exported for ActionScript. In order to work with these instances, they need to be positioned and then event listeners need to be added to each. The following code shows a way to do this without using loops:

package  {
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    public class ManyCircles extends MovieClip {
        public var circle1:BlueCircle;
        public var circle2:BlueCircle;
        public var circle3:BlueCircle;
        public var circle4:BlueCircle;
        public var circle5:BlueCircle;
        public function ManyCircles() {
            _init();
        }
        private function _init():void {
            circle1 = new BlueCircle();
            circle1.x = 50;
            circle1.y = 50;
            circle1.addEventListener(MouseEvent.CLICK, _toggleVisible);
            addChild(circle1);
            circle2 = new BlueCircle();
            circle2.x = 150;
            circle2.y = 50;
            circle2.addEventListener(MouseEvent.CLICK, _toggleVisible);
            addChild(circle2);
            circle3 = new BlueCircle();
            circle3.x = 250;
            circle3.y = 50;
            circle3.addEventListener(MouseEvent.CLICK, _toggleVisible);
            addChild(circle3);
            circle4 = new BlueCircle();
            circle4.x = 350;
            circle4.y = 50;
            circle4.addEventListener(MouseEvent.CLICK, _toggleVisible);
            addChild(circle4);
            circle5 = new BlueCircle();
            circle5.x = 450;
            circle5.y = 50;
            circle5.addEventListener(MouseEvent.CLICK, _toggleVisible);
            addChild(circle5);
        }
        private function _toggleVisible(e:MouseEvent):void
        {
            if (e.target.alpha == 1)
            {
                e.target.alpha = .25;
            } else {
                e.target.alpha = 1;
            }
        }
    }
}

Obviously, you are doing the same actions many times in this example, and if you wanted to change the number of circles, you’d quickly find that the code isn’t very flexible. Using arrays, you can create collections that hold instances of objects for you to work with later. You also can use the array notation as a way to refer to the objects within them, without working with instance names, which gives us a lot more flexibility.

The following is the same application rewritten to take advantage of arrays:

package  {
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    public class ManyCirclesWithLoops extends MovieClip {
        public var circleCollection:Array;

        public function ManyCirclesWithLoops() {
            _init();
        }
        private function _init():void {
            circleCollection = new Array();
            for (var i:uint = 0; i < 5; i++)
            {
                trace("Adding circle #" + i);
                var tempCircle:BlueCircle = new BlueCircle();
                tempCircle.x = 50 + (100*i);
                tempCircle.y = 50;
                tempCircle.addEventListener(MouseEvent.CLICK, _toggleVisible);
                addChild(tempCircle);
                circleCollection.push(tempCircle);
            }
            trace(circleCollection);
        }
        private function _toggleVisible(e:MouseEvent):void
        {
            if (e.target.alpha == 1)
            {
                e.target.alpha = .25;
            } else {
                e.target.alpha = 1;
            }
            trace ("Click on " + e.target + e.target.name);
        }
    }
}

In this example, an array called circleCollection is created for the purpose of holding the new BlueCircle instances. In the initialization function, you have a loop that will run five times. Each time you run the loop, you create a new “fresh” instance of the BlueCircle class, temporarily called tempCircle. You define its parameters, including a dynamic calculation of the x property based on the iterator variable, and add an event listener to the object. You then add the object to the display stack. Before the loop ends, you pass the instance to the circleCollection array using the push() method. This adds the instance to the array and then ends the loop.

After the last execution of the loop finishes, you output the contents of the array.

In the event callback function, you use the event object to toggle the alpha level of the object broadcasting the event. You send a confirmation message to the Output panel as well.

When you run the project, you’ll get something similar to what is shown in Figure 15.4.

Figure 15.4. Output from array example

image

You’ll see that you add each instance of the object, starting with 0 and ending with 4, then you send the entire array to the Output panel, which shows it as a collection of BlueCircle objects.

When you click a circle, the event callback sends a message to the console. You’ll see that you send the object itself first, sending [object BlueCircle]. Then you pass the e.target.name property. This is the instance name assigned to the item. As you know, all objects have an instance name—but in the course of the example, you never had a specific instance name defined. Fear not, an instance name was created automatically for the objects, which you can see is named instance5 and instance3 for the objects that were clicked in this example. Although instance names were created, because you are using the array, you can use the array bracket notation to point to specific objects, or again, to loop through all the objects that you have.

Looping Through an Array

In the previous example, you used loops to build the array, but how do you use them to loop through objects that are already in an array? With the for loop, you can use the iterator and condition test to work with the array’s length property to run for each object in the array. You then use the iterator to select an item from the array using the bracket notation.

Here is an updated example that adds a keyboard event listener to report the status of all the circles in the array:

package  {
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    import flash.events.KeyboardEvent;
    public class ManyCirclesWithLoops extends MovieClip {
        public var circleCollection:Array;
        public function ManyCirclesWithLoops() {
            _init();
        }
        private function _init():void {
            circleCollection = new Array();
            for (var i:uint = 0; i < 5; i++)
            {
                trace("Adding circle #" + i);
                var tempCircle:BlueCircle = new BlueCircle();
                tempCircle.x = 50 + (100*i);
                tempCircle.y = 50;
                tempCircle.addEventListener(MouseEvent.CLICK, _toggleVisible);
                addChild(tempCircle);
                circleCollection.push(tempCircle);
            }
            trace(circleCollection);
            stage.addEventListener (KeyboardEvent.KEY_DOWN, _reportStatus);
        }
        private function _toggleVisible(e:MouseEvent):void
        {
            if (e.target.alpha == 1)
            {
                e.target.alpha = .25;
            } else {
                e.target.alpha = 1;
            }
            trace ("Click on " + e.target + e.target.name);
        }
        private function _reportStatus(e:KeyboardEvent):void
        {
            for (var i:uint = 0; i < circleCollection.length; i++)
            {
                if (circleCollection[i].alpha == 1)
                {
                    trace("Circle " + i + " is solid.");
                } else
                {
                    trace("Circle " + i + " is partially transparent.");
                }
            }
        }
    }
}

When this code runs and you click on a few circles and then press a key on the keyboard, the Output panel will display something similar to the following:

Adding circle #0
Adding circle #1
Adding circle #2
Adding circle #3
Adding circle #4
[object BlueCircle],[object BlueCircle],[object BlueCircle],[object BlueCircle],[object BlueCircle]
Click on [object BlueCircle]instance3
Click on [object BlueCircle]instance5
Circle 0 is solid.
Circle 1 is partially transparent.
Circle 2 is partially transparent.
Circle 3 is solid.
Circle 4 is solid.

When you press a key on the keyboard, the callback function springs to life and loops through each object in the array, starting with element 0. Ultimately the loop ends when the iterator is equal to the length property of the array. Remember, this works because the first element is numbered 0, not 1.

Wrapping Up

In this chapter, you learned how to repeat actions using loops. You covered two types of loops: the for loop where you define your iterator variable, condition test, and step for the loop; and the do loop that allows your loop to run at least once and then tests a condition at the end of the loop.

In addition to loops, you also covered how you can create arrays, or collections of objects, including objects that you display on the Stage. Using these arrays, you can then loop creation and manipulation actions across the items in the collection to make repetitive actions easier to manage.

Here are some tips to help make working with loops and arrays easier:

• To loop through a collection of ActionScript commands a specific number of times, use the for loop.

• The for loop requires three parameters: the iterator variable, the condition test, and the step. Each are separated by semicolons in the loop definition.

• For a loop that you want to run at least once, consider the do loop.

• A do loop tests the conditional at the end after the while statement.

• Remember to check your condition test to ensure that it will exit at some point; otherwise you have an infinite loop that will run forever.

• You can nest loops within each other; just make sure you manage your iterators and keep the loops entirely self-contained.

• Creating an array allows you to have a name for a collection of objects.

• Access objects within the array using bracket notation and identify an element index number.

• Use the push() method to add items to the array.

• Use the splice() method to remove one or more items from the array.

• Remember that the first item in an array has the element index number 0.

• The length property of an array returns the number of items in the array. Use this number to help loop through objects in an array using a for loop.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.57.16