Understanding Loops with Arrays

There is a very short list of programming structures you have to learn to be reasonably comfortable in most modern object-oriented languages. Arrays are one of them. Loops are another. i covered both of these structures in the previous aptly-named articles Understanding Arrays and Understanding Loops.

Now that we understand loops, and we understand arrays, we’re ready to smack their featureless plastic genitals together like we’re making Barbie have babies.

Wonder Twins

(Which one of these is the chick again?)

Arrays really come alive with Loops. By using an Array’s length property as the loop limiter, we can step through every element in an Array one by one.

Here’s what that looks like in code:

var myArray:Array = new Array("Nigel Tufnel", "Derek Smalls", "David St. Hubbins");
 
var i:int =0;
for(i=0; i<myArray.length; i++)
{
    trace(myArray[i]); // This prints each element in the array, one by one, to the console/output window 
}

Note: If you’re using Unity javascript, try print or Debug.Log instead of trace.

If you truly understand Loops, this shouldn’t be too challenging for you. Instead of using some arbitrary value like one thousand as our limiter, we’re using the array’s length property, which is the number of elements in the array. This property is dynamic, so that any time we add things to our array, or take them away, length is updated for us. We don’t have to rely on a hard-coded value (which means a number that doesn’t change).

The code snippet shown above traces out each element in the array, one after the other:

  • Nigel Tufnel
  • Derek Smalls
  • David St. Hubbins

This is because on every iteration of the loop, our iterator variable called i is increased by one.

i begins life with a value of 0. On the first run through the loop, the code interpreter resolves myArray[i] to myArray[0]. The first element in the array, at index 0, is “Nigel Tufnel”, so that’s what you’ll see in the output console.

On the next iteration, i gets jacked up to 1. The element at index 1 in the array is “Derek Smalls”, so that’s what prints out.

Finally, in the third and final round, we print out “David St. Hubbins”, because myArray[i] resolves to myArray[2]. The element at index 2 of the array is “David St. Hubbins”.

After that, the interpreter bounces back to the top of the loop. i is incremented to 3. We check the limiter:

i < myArray.length

Because i is 3 and myArray.length is also 3, this line resolves to 3 < 3. Since 3 is not less than 3, the answer here is false. And because the answer is false, the code interpreter is not allowed to go through the loop any more. It happily exits the loop and starts chewing through the code beneath the bottom closed curly brace that ties up the loop.

Protip: If you’re a stickler for speed, it’s marginally faster to store myArray.length in a variable, to prevent your interpreter from having to do the length calculation on every iteration of your loop. Here’s what that looks like:

var myArray:Array = new Array("Nigel Tufnel", "Derek Smalls", "David St. Hubbins");
 
var i:int =0;
var len:int = myArray.length;
for(i=0; i<len; i++)
{
    trace(myArray[i]);
}

We store myArray.length in a variable called len, and then refer to that variable in the limiter section of the loop header.

For even more of a tiny speed increase, do away with the new keyword and declare the array like this:

var myArray:Array = ["Nigel Tufnel", "Derek Smalls", "David St. Hubbins"];

Who Cares?

This is all still pretty pointless. When are you ever going to use this when programming a game? Well, for the rest of the article, i’ll lay some real-world examples on you to give you an idea of how to maximize the wonderful union of Loops with Arrays.

Think of any situation in a video game when you have a list of similar things. In a first person shooter, you need to keep track of all the bullets that get fired. Makes sense to create an array to store all of those bullets. You can add bullets to the list and remove them from the list using the Array class methods we looked at in the Understanding Arrays article.

Most games run on one giant loop, with an Update process and a Draw process. Update figures out where everything should be, and Draw renders those things to the player’s view. If you want to update the positions of all the bullets, you may need to use a For Loop to loop through your collection of bullets and move them one tiny bit. Then in the Draw process, you loop through your list of bullets and render them to the screen. When you repeat these processes quickly enough, you get the illusion of animation.

Black Ops

We might keep separate lists of the bullets, the enemies, the friendlies, and the bomb shells.

Very often, you’ll use a loop to create the initial array of objects, and then more loops later to pick through that list. Here’s an example of two functions. One initializes all of the monsters, and the other kills all of the monsters (assuming the player just used the “Kill All Monsters” megabomb power-up).

var aMonsters:Array; // this array is a bucket that can hold many things: namely, monsters.
 
function initMonsters():void
{
     aMonsters = [];  // Defines an empty instance of the Array class.
     var totalMonsters:int = 50; // this is a variable (bucket) that contains the number of monsters we'd like to begin with
     for(var i:int = 0; i<totalMonsters; i++)
     {
         aMonsters.push(new Monster()); // Creates a new instance of the Monster class, and adds that instance to the aMonsters array.  
         // If that's confusing to you, we can split this up into two separate lines:
         // var monster:Monster = new Monster();
         // aMonsters.push(monster);
     }
}
 
function killAllMonsters():void
{
     var len:int = aMonsters.length; // store the length of the aMonsters array in a variable called len.
     // By doing this, we speed up our loop ever so slightly.
     for(var i:int = 0; i<len; i++)
     {
         var monster:Monster = aMonsters[0]; // stores a reference to the first monster in the array
         monster.die(); // calls some sort of death method on the monster instance
         aMonsters.shift(); // removes the first element of the array.  The aMonsters array gets shorter and shorter every time we loop, as we remove monster after monster.  By the end of this loop, the aMonsters array is empty.
     }   
}

Note: If some of the initialization stuff here looks a bit spooky, try reading the Understanding Classes series. Hopefully you’re catching what i’m throwing regarding loops and arrays, even if the class stuff is a little unfamiliar.

For Unity javascript: Everything here is almost identical … the main difference is that methods like push begin with capital letters.

Those double-slashes, by the way, are comments. They are ignored by the compiler, and are added to clarify the code.

Get Carded

Here’s another example. Let’s say we’re programming a card game. We can use an array to store our deck of cards. Each element in the array is a card. We use one loop to build the deck. Then we shuffle the deck. Finally, we use a loop to deal some cards onto the table, using the Array.shift() method to deal off the top of the deck. This removes the cards from the array one by one, and adds them to a different array called aCardsOnTable.

var aDeck:Array; // declare an array to hold all the cards
var aCardsOnTable:Array; // declare an array to hold the cards that we deal out
 
function buildDeck():void
{
    aDeck = []; // create an empty instance of the Array class and store it in a variable called aDeck
    var totalCards:int = 52; // we want 52 cards in the deck, so that's how many times we'll loop
    for(var i:int=0; i<totalCards; i++)
    {
         aDeck.push(new Card()); // we instantiate the Card class, and add the new card instance to the aDeck array.
         // Once again, if we're doing too much in this line for you to follow along, here's a longer version of the same code in two steps:
        // var card:Card = new Card(); // create the card instance and store it in a variable
        // aDeck.push(card); // add the card instance to the aDeck array
    }
    shuffle(aDeck); // this is a custom function that you'll probably have to write yourself (just like the Card class).  It randomizes all of the elements in the array.
}
 
function dealCards():void
{
    aCardsOnTable = []; // define aCardsOnTable as an empty array
    var numCardsToDeal : int = 5; // Let's deal 5 cards to the table.
    for(var i:int=0; i<numCardsToDeal; i++)
    {
         aCardsOnTable.push(aDeck.shift()); // pulls the first element out of aDeck, and adds it to aCardsOnTable
         // That's a bit of shorthand.  Let me blow that line out into separate steps in case you're having trouble following it:
         // var topCard:Card = aDeck.shift();  // use shift to pull out the first card in the aDeck array, and store it in a variable called topCard
         // aCardsOnTable.push(topCard); // add the card we removed to the end of the aCardsOnTable array.
    }
    // When we finish with this loop, there are 5 cards in the aCardsOnTable array,
    // and 47 cards left in the aDeck array.
    // This is a great way to deal out cards!   By removing a card from the aDeck array each time using shift(), we ensure that we'll never deal the same card twice.
}

Those previous two examples are very similar. Here’s another real-world example that’s slightly different.

Looping Through Movieclips on the Stage

Super eggheads like to lay out their GUIs (graphical user interfaces – buttons and windows and text boxes and junk) entirely in code. i don’t prefer to do it that way, because i’m a very visual person, and i like to see my interface laid out on-screen. i like to be able to poke, prod and nudge things around visually.

So often, i’ll have a bunch of buttons on the stage. The buttons all have instance names. i’ll put those instance names in an array, and then loop through the array to add standard buttonMode, rollover and rollout effects to all the buttons in one shot. Here’s how that looks, presuming i have the buttons “phyiscally” on my stage and named properly:

 
 
// i call the initBtns function somewhere in my code
 
function initBtns():void
{
    var aBtnNames:Array = ["btnPlay", "btnQuit", "btnCredits"]; // we store the instance names of my on-stage buttons in an array
 
    var len:int = aBtnNames.length; // Let's dynamically loop through as many buttons as we have in the array.
    for(var i:int=0; i<len; i++)
    {
         activateBtn(this[aBtnNames[i]]);
         // Here's a slower, possibly clearer way to say that:
         // var btnName:String = aBtnNames[i]; // Refers to the i'th element of the array
         // var btn:MovieClip = this[btnName] // Refers to a movieclip instance on stage with that name
         // activateBtn(btn); // Passes the reference to that button to the activateBtn function
    }
}
 
function activateBtn(btn:MovieClip):void
{
     // This is standard stuff i want all of my buttons to do:
     btn.buttonMode = true;
     btn.mouseEnabled = true;
     btn.mouseChildren = false;
     btn.addEventListener(MouseEvent.MOUSE_OVER, rollOverBtn);
     btn.addEventListener(MouseEvent.MOUSE_OUT, rollOutBtn);
}

Of course, an even better way to handle this button situation is to create your own custom button class, but we’re taking baby steps here. That’s the thing about code – these pieces we’re learning are like Lego blocks. There are tons of different ways to build a sculpture out of Lego. There are no “right” ways – only preferred ways. Use this Understanding … series to get a grip on all the blocks you have to play with, and then … it’s time to play!

Lego Escher

(We’ll work our way up to this.)

For more Flash AS3 Tutorials and a pile of other useful stuff, check out our Flash and Actionscript 911 feature.

8 thoughts on “Understanding Loops with Arrays

  1. Arthur Marris

    Again Ryan, great tutorial. I was very interested in the multiple ways loops and arrays can be used. I like how your giving tips for unity users too. Thanks!

    Reply
    1. Ryan Henson Creighton

      Thanks, Arthur. i’m planning a final post called Putting It All Together which uses all of the basic code constructs in a (sort of) real-world scenario. Stay tuned.

      Reply
  2. Brett

    In your last example, could we get a sample for how the rollOverBtn and rollOutBtn functions would be written? Please?

    BTW, Love the writing style. Its rare that someone uses their wit not only to entertain, but to inform! Awesome.

    Reply
    1. Ryan Henson Creighton

      Thanks for the compliment, Brett! Anything for you!

      private function rollOverBtn(e:Event):void
      {
          var btn:MovieClip = e.target as MovieClip; // get a reference to the button using the Event instance
          btn.gotoAndStop("over"); // (or whatever you want the button to do at this point)
      }
      Reply
  3. Pete

    Forgive me –

    function killAllMonsters():void
    {
         var len:int = aMonsters.length; // store the length of the aMonsters array in a variable called len.
         // By doing this, we speed up our loop ever so slightly.
         for(var i:int = 0; i&lt;len; i++)
         {
             var monster:Monster = aMonsters[0]; // stores a reference to the first monster in the array
             monster.die(); // calls some sort of death method on the monster instance
             aMonsters.shift(); // removes the first element of the array.  The aMonsters array gets shorter and shorter every time we loop, as we remove monster after monster.  By the end of this loop, the aMonsters array is empty.
         }   
    }

    This code is actually wrong, isn’t it?

    Let’s walk through two iterations of the loop, first and second, with an array of >3 length, and the first three elements are monsters “lenny”, “carl”, and “bruce”.

    The first iteration i = 0 and [0] = “lenny”, and lenny is removed. i is incremented at the end and is now 1, but carl is now [0] and bruce is now [1]

    2nd iteration i = 1, [0]=carl and [1]=bruce, correct?

    var len isn’t updated inside the loop, so once it’s set to the original array.length, it remains the original array.length.

    for(var i:int=myArray.length -1; i&gt;=0; --i) {
    myArray.[i].removeMethod();
    myArray.pop();

    This method starts at the end (i’s initial value is the last index in the array)),
    tells the object at the end of the array to get ready to die with that object’s death method,
    removes the last element with array.pop() (pop removes the very last element of an array)
    and i is decremented 1, and becomes the new last element of the array.
    when i is <0 there are no more elements and the loop will stop, because the array will be emtpy.

    Reply
    1. Ryan Henson Creighton

      Good catch, Pete! The easy fix is just to update len inside the loop. i’ll go back and edit the article.

      Reply
    2. Ryan Henson Creighton

      AH wait – i just re-read this carefully. i haven’t tested your code … it probably works … but when i was just starting to get up to speed with code, i found that any time i tried to pull fancy acrobatics by counting down in my loop, or doing interesting things with the limiter, i’d get lost and confused. Believe it or not, 99% of the time, your plain old vanilla (i=0; i<len; i++) loop header structure will work perfectly.

      In this case, we don't have a problem. We start by storing the length of the array – say, 3. So we're only going to loop 3 times, one for each monster. Is that accurate? Is that what we want to do? Yes, it is. So the code so far is correct.

      Inside the loop, we refer to the monster at position 0. In your example, that monster is named "Lenny". We kill Lenny, and then we shift the array. What shift() does is it removes the first element in the array. So now, the array contains "Carl" and "Bruce".

      How many more times are we going to loop through the array? Two. i counts up to 1 on our second loop, but the value of i doesn't really matter at all, because we never actually use it in the loop body. i is simply keeping count. We're only ever referencing the first element in the array, at position 0.

      Second time, we get a reference to the first monster in the array at position 0, Carl. We kill Carl. We shift the array. Now it contains one element.

      How many more times are we going to loop through the array? One.

      The last time through, the monster in the first position is named Carl. We kill him. We shift the array – now it contains zero elements.

      How many more times are we going to loop through the array? None. We're finished.

      Yeah?

      Reply
  4. Pingback: problem mit ansprechen eines mc - Flashforum

Leave a Reply to Pete Cancel reply

Your email address will not be published. Required fields are marked *