Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning ActionScript 2.0 2006

.pdf
Скачиваний:
101
Добавлен:
17.08.2013
Размер:
12.47 Mб
Скачать

Chapter 3

It is worth mentioning that the loop could have checked the length of the array directly each time:

for (var i:Number = 0; i < fruitArray.length; i++)

Instead, the length of the array was saved to a temporary local variable, and that variable was used in the stop-loop test. Local variables are implemented in the player using features of the computer’s processor that speed up access to the variables. The difference is not noticeable for small numbers of loops, but for intensive looping operations, it helps measurably.

A for loop can be applied for purposes other than managing arrays. The Fibonacci sequence, for example, is a mathematical sequence of numbers that follow a pattern. Each number is the sum of the two preceding numbers, where the first two numbers in the series are defined as 0 and 1. This sequence yields a pattern that has many important applications in both nature and in pure mathematics. To get the value for any particular number in the series, a number of additions need to be done beforehand. This is a perfect task for the for loop:

var sequenceLength:Number = 10; var number1:Number = 0;

var number2:Number = 1; var currentNumber:Number;

for (var i:Number = 3; i <= sequenceLength; i++)

{

currentNumber = number1 + number2; number1 = number2;

number2 = currentNumber;

trace(“Fibonacci #” + i + “: “ + currentNumber);

}

//Outputs:

//Fibonacci #3: 1

//Fibonacci #4: 2

//Fibonacci #5: 3

//Fibonacci #6: 5

//Fibonacci #7: 8

//Fibonacci #8: 13

//Fibonacci #9: 21

//Fibonacci #10: 34

This loop does not start at zero, as most other for loops do. The first two terms (0 and 1) are given, not calculated, so it is only necessary to start calculating for the third term. Also, you’re not working with an array, which always starts at index 0 as the first element. As a result, when i = 3, you actually do have the third term in the sequence. When i = sequenceLength, the loop should proceed with that last iteration rather than stopping, as opposed to an array where you want to stop at the index arrayLength – 1.

Another useful application of the for loop is for creating and initializing multiple movie clips. The following example creates 10 movie clips, positions them, and draws a square inside each one:

var movieClipHandle:MovieClip;

var baseMovieClip:MovieClip = _level0; var numMovieClips:Number = 10;

for (var i:Number=0; i < numMovieClips; i++)

{

baseMovieClip.createEmptyMovieClip(“movieClip” + i, i);

68

Understanding ActionScript Expressions and Loops

movieClipHandle = baseMovieClip[“movieClip” + i]; movieClipHandle._x = i * 20;

movieClipHandle._y = 0; movieClipHandle.lineStyle(1, 0x000000, 100); movieClipHandle.moveTo(0, 0); movieClipHandle.lineTo(0, 10); movieClipHandle.lineTo(10, 10); movieClipHandle.lineTo(10, 0); movieClipHandle.lineTo(0, 0);

}

//Output:

//Creates ten empty movie clips, places them 20 pixels apart along the top of

//the stage, and draws a 10x10-pixel square inside each one.

The first line creates a variable used to temporarily hold each movie clip, the second one creates a temporary handle to the root movie clip that contains each movie clip being created, and the third sets how many movie clips you want to create. For each iteration of the loop, it creates an empty movie clip, saves a temporary handle to that clip, moves the clip 20 pixels to the right of the previous clip, and draws four lines inside it to make the square.

The for..in Loop

The for loop may be the programmer’s workhorse, but the for..in loop is a little more specialized although still extremely useful. This loop is the companion to the associative array and the object collection. Most arrays are indexed numerically, so myArray[0] gets the first chunk of data, myArray[1] gets the second, and so on. Associative arrays, you recall, allow data to be indexed by strings instead of by numbers and are used to store relationships between pieces of data. Objects group a set of properties and corresponding values together into property/value pairs. (Associative arrays and object collections are examined in the “Working with Collections of Data” section earlier in this chapter.) The base syntax for the for..in loop is as follows:

for (var iterator:String in collectionObject)

{

// Statements

}

The collectionObject variable can be any associative array or object collection. The iterator variable is a temporary variable used just within the for loop. With each time through, the iterator holds the name portion of each name/value pair, which is used to retrieve the corresponding value. Here’s an example:

var labelArray = new Array(); labelArray[“car”] = “Voiture”; labelArray[“truck”] = “Camion”; labelArray[“motorcycle”] = “Motocyclette”; labelArray[“bicycle”] = “Bicyclette”;

for (var labelId:String in labelArray)

{

trace(“id: “ + labelId + “ translation: “ + labelArray[labelId]);

69

Chapter 3

}

// Outputs:

//id: bicycle translation: Bicyclette //id: motorcycle translation: Motocyclette //id: truck translation: Camion

//id: car translation: Voiture

Notice that the order of the output in this example is reversed from the order in which the associative array elements were assigned. Do not rely on associative arrays for maintaining any specific order.

Associative arrays are also very useful for maintaining a simple database of records. The for..in loop can be used to loop through records, looking for ones with specific characteristics:

var photoListing = new Object();

photoListing[“whiteLanding”] = {title:”White Landing”, width:1024, ; height:768, size:123};

photoListing[“texture1”] = {title:”Study in Texture 1”, width:1024, ; height:768, size:186};

photoListing[“texture2”] = {title:”Study in Texture 2”, width:1280, ; height:1024, size:195};

photoListing[“kitsSunset”] = {title:”Sunset on Kits Beach”, width:1280, ; height:1024, size:325};

photoListing[“studyInGrey”] = {title:”Study in Grey”, width:1024, ; height:768, size:144};

for (var photoId:String in photoListing)

{

if (photoListing[photoId].size < 200 && photoListing[photoId].width <= 1024)

{

trace(“Photo matches criteria: “ + photoId);

}

}

//Outputs:

//Photo matches criteria: studyInGrey

//Photo matches criteria: texture1

//Photo matches criteria: whiteLanding

This example loops through an associative array looking for records with specific criteria (size less than 200 and width less than or equal to 1024). It outputs the ID of each matching record it finds. Code could easily be added to do a more involved task, such as add a thumbnail of the associated photo into a search results area.

The while Loop

Like the for loop, the while loop keeps iterating through a series of statements until a specific condition is met. However, the while loop is better suited for situations where the termination condition relies on something more complex than the value of a single integer variable.

70

Understanding ActionScript Expressions and Loops

The basic syntax of the while loop is as follows:

while (condition)

{

//statements

}

The execution of the loop is very simple. As long as the condition evaluates to true, the statements continue to execute. Here’s the order of the loop’s execution:

1.The condition is evaluated.

2.If the condition evaluates to true, the statement block is executed. (If the condition evaluates to false, the loop halts, and the next line of code outside of the closing bracket is executed.)

3.Return to step 1.

The while loop can be used to exactly duplicate the behavior of the for loop:

var fruitArray:Array = new Array(“Apple”, “Orange”, “Pear”); var i:Number = 0;

while (i < fruitArray.length)

{

trace(fruitArray[i]);

i++;

}

//Outputs:

//Apple

//Orange

//Pear

This code is not quite as compact as the for loop, and is a little more prone to simple programming errors. If the i++; statement is left out by accident, for instance, an infinite loop results, and would require a forceful closing of the movie to terminate. You cannot get into that circumstance with the for loop because the compiler displays a warning about the missing iterator and prevents the compilation from even happening.

A better example of the while loop is where the termination condition is more complex, and where it is not known in advance how many times the loop should run:

var stopCharacter:String = “.”;

var paragraphText:String = “The quick brown fox. Jumped over the lazy dog.”; var sentenceText:String = “”;

var i:Number = 0;

while (i < paragraphText.length && paragraphText.charAt(i) != stopCharacter)

{

sentenceText += paragraphText.charAt(i); i++;

}

71

Chapter 3

trace(“Sentence: “ + sentenceText);

//Outputs:

//Sentence: The quick brown fox

This while loop is designed to extract the first sentence from a string of text. It compares each character in the string, looking for a period. When it finds one, it stops execution and outputs the text leading up to the period. If the loop finds no periods in the text, it stops when it runs out of letters to compare and returns the whole string.

The while loop is quite powerful, but it is not as commonly used as the for loop: It is more complex, more prone to runtime errors, and often unnecessary. Before implementing a while loop, consider whether a for loop would better serve the purpose.

The do..while Loop

The do..while loop is almost identical to the while loop, in that it continues to loop until a specific condition has been met. It is different only in the order that the loop evaluation happens. A while loop evaluates the condition before executing the statements in the loop block; a do..while loop evaluates the condition after executing the statements. One of the side effects of this behavior is that the statement block is guaranteed to execute at least once.

The basic syntax for the do..while loop is as follows:

do

{

//statements

}

while (condition)

Here’s the order in which a do..while loop runs:

1.The statement block is executed.

2.The condition is evaluated.

3.If the condition evaluates to false, the loop halts, and the next statement after the while statement is executed. If the condition evaluates to true, the loop returns to step 1.

The example while loop can be reworked a little bit to make it into a do..while loop:

var stopCharacter:String = “.”;

var paragraphText:String = “The quick brown fox. Jumped over the lazy dog.”; var sentenceText:String = “”;

var i:Number = 0;

do

{

sentenceText += paragraphText.charAt(i); i++;

}

while (i < paragraphText.length && paragraphText.charAt(i) != stopCharacter)

72

Understanding ActionScript Expressions and Loops

trace(“Sentence: “ + sentenceText);

//Outputs:

//Sentence: The quick brown fox

This is almost identical to the previous example. The difference is that it examines the first character before testing the termination condition. This alternate syntax really is not very helpful, especially because if the string is empty, it still tries to access the first (non-existing) character. In practice, this loop is used very rarely. You are always better off using a while loop instead.

Try It Out

Using Arrays to Track Data

In this project, you work with indexed arrays, associative arrays, and objects, as well as loops and conditional logic.

1.Create a new Macromedia Flash document by selecting File New and choosing Flash Document from the New Document panel.

2.Click the first frame in the timeline, open the Actions panel (Window Development Panels Actions), and type in the following ActionScript code:

#include “tryItOut_trackData2.as”

3.Select File Save As, name the file tryItOut_trackData2.fla, choose an appropriate directory, and save it.

4.Create a new script file by selecting File New and choosing ActionScript File from the New Document panel.

5.Select File Save As and ensure it is showing the same directory containing the .fla file. Name the file tryItOut_trackData2.as and save it.

6.Enter the following code into the new ActionScript file:

//Set up array for tracking numbers and total weight for each type of vehicle

var vehicleTotals:Array = new Object();

vehicleTotals[“car”] = { totalCategoryNumbers:0, totalCategoryWeight:0 }; vehicleTotals[“pickup”] = { totalCategoryNumbers:0, totalCategoryWeight:0 }; vehicleTotals[“semi”] = { totalCategoryNumbers:0, totalCategoryWeight:0 };

//Track total weight of all vehicles var totalWeight:Number = 0;

//Set up array holding information about each vehicle var vehicleArray:Array = new Array();

vehicleArray.push( { id:”345”, type:”car”, weight:1218 } ); vehicleArray.push( { id:”730”, type:”pickup”, weight:1684 } ); vehicleArray.push( { id:”312”, type:”semi”, weight:14456, cargo:11023 } ); vehicleArray.push( { id:”943”, type:”car”, weight:1306 } ); vehicleArray.push( { id:”109”, type:”car”, weight:16349 } );

//Save total number of vehicles to a variable for use in loop.

var numVehicles:Number = vehicleArray.length;

// A temporary variable for convenience

73

Chapter 3

var currentVehicleType:String;

// Iterate through each vehicle

for (var i:Number = 0; i < numVehicles; i++)

{

//Get the type of this vehicle, and save it to a temporary

//variable to help make the code more readable currentVehicleType = vehicleArray[i].type;

//Add weight of this vehicle to total weight. totalWeight += vehicleArray[i].weight;

//Add one to the number tracking this type of vehicle. vehicleTotals[currentVehicleType].totalCategoryNumbers += 1;

//Add this vehicle weight to the number tracking total weight

//of this type of vehicle. vehicleTotals[currentVehicleType].totalCategoryWeight += ;

vehicleArray[i].weight;

//If the vehicle is a semi, add the weight of its cargo

if (currentVehicleType == “semi”)

{

totalWeight += vehicleArray[i].cargo; vehicleTotals[currentVehicleType].totalCategoryWeight += ;

vehicleArray[i].cargo;

}

}

// Iterate through each type of vehicle for (vehicleType in vehicleTotals)

{

trace(“Number of “ + vehicleType + “s: “ + ; vehicleTotals[vehicleType].totalCategoryNumbers);

trace(“Total weight of “ + vehicleType + “s: “ + ; vehicleTotals[vehicleType].totalCategoryWeight);

}

trace(“Sum of vehicle weights: “ + totalWeight);

7.Save the file (File Save), return to the Flash project file, and select Control Test Movie.

How It Works

This program creates two arrays, one to hold data about each vehicle, and one to hold calculated data about each group of vehicles. It begins by creating an associative array to store data about the different types of vehicles and then creates an object for each vehicle type, initializing each object property to zero:

var vehicleTotals:Array = new Object();

vehicleTotals[“car”] = { totalCategoryNumbers:0, totalCategoryWeight:0 }; vehicleTotals[“pickup”] = { totalCategoryNumbers:0, totalCategoryWeight:0 }; vehicleTotals[“semi”] = { totalCategoryNumbers:0, totalCategoryWeight:0 };

74

Understanding ActionScript Expressions and Loops

The program initializes a counter to track the total vehicle weight and total number of vehicles, and it sets up the data for each individual vehicle using an indexed array of objects. Each row contains information about one specific vehicle. In cases where an array stores a series of records, each row usually has a unique ID. In this instance, the ID is not used anywhere, but it would normally be used to allow a search for information on a specific vehicle, or to relate the record to some other data, such as data on a server.

var vehicleArray:Array = new Array();

vehicleArray.push( { id:”345”, type:”car”, weight:1218 } ); vehicleArray.push( { id:”730”, type:”pickup”, weight:1684 } ); vehicleArray.push( { id:”312”, type:”semi”, weight:14456, cargo:11023 } ); vehicleArray.push( { id:”943”, type:”car”, weight:1306 } ); vehicleArray.push( { id:”109”, type:”car”, weight:16349 } );

It then loops through each vehicle, updating the variables’ tracking numbers and weight accordingly. First it stores the type of the current vehicle being checked in a variable, just to make subsequent lines a bit cleaner:

currentVehicleType = vehicleArray[i].type;

It adds the weight of the vehicle to the variable tracking the total weight:

totalWeight += vehicleArray[i].weight;

And it then updates the tallies for the appropriate vehicle type:

vehicleTotals[currentVehicleType].totalCategoryNumbers += 1; vehicleTotals[currentVehicleType].totalCategoryWeight += vehicleArray[i].weight;

Semis have an additional cargo weight property, so that value is added to the total as well:

if (currentVehicleType == “semi”)

{

totalWeight += vehicleArray[i].cargo; vehicleTotals[currentVehicleType].totalCategoryWeight += ;

vehicleArray[i].cargo;

}

Finally, it iterates through each vehicle type, reports their stats, and reports the overall total weight:

// Iterate through each type of vehicle for (vehicleType in vehicleTotals)

{

trace(“Number of “ + vehicleType + “s: “ + ; vehicleTotals[vehicleType].totalCategoryNumbers);

trace(“Total weight of “ + vehicleType + “s: “ + ; vehicleTotals[vehicleType].totalCategoryWeight);

}

trace(“Sum of vehicle weights: “ + totalWeight);

75

Chapter 3

The results in the output panel should look something like the following:

Number of semis: 1

Total weight of semis: 25479

Number of pickups: 1

Total weight of pickups: 1684

Number of cars: 3

Total weight of cars: 18873

Sum of vehicle weights: 46036

Dealing with Loop Errors

As much as you’d like each of your loops to work the first time, you will likely face a number of problems. Some won’t be apparent unless you actually carefully examine your program’s output, whereas others will cause your program to grind to a halt and stop responding completely. Developing debugging strategies is important to finding and fixing these problems, and both the trace statement and the debugger panel are instrumental in troubleshooting. (Chapter 27 includes tips for effective debugging.) The following sections examine off-by-one errors and infinite loops, providing some strategies for dealing with these errors.

Off-by-One Errors

Remember, almost all of your loops will start at zero, not at one. All indexed arrays are zero-based, which means that the first element is at position 0, the second element is at position 1, and so on until the last element, which will be at position arrayLength – 1. If the wrong expression is used for the condition, the loop goes out of the bounds of the array. Here’s an example:

var fruitArray:Array = new Array(“Apple”, “Orange”, “Pear”); var numFruit:Number = fruitArray.length;

for (var i:Number = 0; i <= numFruit; i++)

{

trace(i + “: “ + fruitArray[i]);

}

//Outputs:

//0: Apple

//1: Orange

//2: Pear

//3: undefined

In this traced code, you see that there are only three elements in the array, but the loop has tried to access the array four times. The first three iterations work fine, but when i reaches 3, the condition 3 <= 3 returns true and allows the loop to continue for a fourth iteration. The trace() statement then attempts to access position 3 within the array, which is really element 4, and because that exceeds the bounds of the array, the attempt to access the element returns the keyword undefined. Using the wrong loop termination operator is a common mistake and is frequently referred to as an off-by-one error. To guard against this, use trace() statements to test whether you are getting the expected results both at the beginning and at the end of your loops. If you stick to the tried-and-true format of for (var i:Number = 0; i < arrayLength; i++), you should rarely go wrong.

76

Understanding ActionScript Expressions and Loops

Infinite Loops

The bane of developers is the infinite loop — the loop’s termination condition never evaluates to false, so the loop never stops running. The result is that code statements that should be executed do not, yet the processor is pushed to the limit. Macromedia Flash Player and the Macromedia Flash development environment help mitigate the effects of an infinite loop enough so that you can escape from a stuck project. If a loop continues for a given period of time, usually around 20 seconds, the player shows a warning (see Figure 3-4) and gives you an opportunity to shut down the movie. Unfortunately, the mechanism to abort an infinite loop does not always work, and sometimes the only option is to forcequit the browser or the development environment.

Figure 3-4

Infinite loops occur most frequently in while loops. Take a look at the following loop:

var i:Number = 0;

var numIterations:Number = 100;

while (i < numIterations)

{

trace(i);

}

This simple example results in an infinite loop because the iterator variable i never changes, so i<numIterations never evaluates to false and the trace() statement continuously outputs zero. All that’s needed to fix this is the addition of a single line that increments the iterator i:

var i:Number = 0;

var numIterations:Number = 100;

while (i < numIterations)

{

i++;

trace(i);

}

A slightly more complex example is more difficult to debug:

var stopCharacter:String = “.”;

var paragraphText:String = “The quick brown fox”; var sentenceText:String = “”;

77