Putting buttons in an array is such a cool technique, that I can kind of guarantee that once you get to using it, you'll want to use it for everything!
Let's start with a simple example so that I can really clue you in to just how useful this is. Suppose that you have a fla file for a website. In your fla file, you've created five buttons. Each button is actually a MovieClip instance. Whether they are all instances of the same MovieClip symbol is irrelevant. What's relevant is that they have all been created in the authoring tool, and that they all exist on the stage. If the code is going to be on frame 1 (we'll assume it is), then the buttons should all exist on frame 1 too, otherwise you will get null object reference errors.
Anyway, let's say that your buttons are named:
The point is that the names could be anything at all (they don't have to be numbered in sequence like the former btn0, btn1, btn2, etc). We will put them in an array, and after we do, it will be easy to treat them as a group instead of a bunch of unrelated buttons. So let's create an array and add our buttons to the array:
var clipArray:Array = [home_mc, about_mc, products_mc, services_mc, contact_mc];
One mistake beginning programmers make is to assume that arrays can only store string values (no offense, I used to think of arrays that way, too!). So they proceed to give all their MC buttons names so that they can store the names in the array, then they use perhaps getChildByName("theName") to get references to their buttons. But arrays can store any and all kinds of values. So why not store the MovieClip instances themselves, rather than string values? In fact, I don't so much think of the array as "storing" the values--rather I think of it as giving all the values a new set of names. Here's what I mean. After that above line of code is run:
So, I want you to get this mental picture: putting all of these buttons into an array didn't cause them to get scooped up and placed somewhere else, as if they had moved or something. Let's take home_mc for example. I can still use the name home_mc even after I have put home_mc in the array:
home_mc.addEventListener(MouseEvent.CLICK, clickHandler); function clickHandler(event:MouseEvent):void { this.gotoAndStop("home"); }
But now I can also use home_mc's new alternate name to do the same thing:
clipArray[0].addEventListener(MouseEvent.CLICK, clickHandler); function clickHandler(event:MouseEvent):void { this.gotoAndStop("home"); }
This is the part I want you to get: clipArray[0], for all practical purposes, is home_mc. Everything that you could do with home_mc, using all of the properties and methods of MovieClips, you can now also do using clipArray[0] instead! So to move home_mc twenty pixels further down, you can do this:
clipArray[0].y += 20;
I could go on and on with more examples of properties and methods you can use (the whole list of MovieClip properties and methods!), but I think by now you get the central idea. Each mc button can now be programmed using the array name and index number instead.
Where this really comes in handy is when you combine arrays and loops. Arrays have a length property that you can use to know how many times to loop. This makes for dynamic code that need only be written once. For example:
var clipArray:Array = [home_mc, about_mc, products_mc, services_mc, contact_mc]; for(var i:int = 0; i < clipArray.length; i++) { clipArray[i].buttonMode = true; clipArray[i].addEventListener(MouseEvent.CLICK, clickHandler); } function clickHandler(event:MouseEvent):void { trace("you clicked " + event.target.name); }
In the above code, the loop is run five times. Each time through the loop, the loop counter "i" is incremented by one. So the first time through the loop, we are dealing with clipArray[0], which corresponds to home_mc. So home_mc's buttonMode property is set to true, giving it a hand cursor, and an event listener for a mouse click (clickHander) is added to home_mc. The next time through the loop, i will equal 1, and the same actions will be performed for about_mc. And so on for the rest of the loop, until all of the buttons have been programmed in the same way.
Suppose that later on, you add another mc button called links_mc. Now all you would have to do is add links_mc to the end of the array. There would be no need to change the for loop at all. Since the loop is based on the array's length, it will now automatically include links_mc, which will get the same programming as all the other buttons (but we won't add links_mc right now).
I am aware that the same event listener has been added to all of the buttons, and you may be wondering how to make individualized actions happen inside the listener, based on which button was clicked. One answer is to either use if statements, or a switch statement, that compares each button to event.currentTarget (you could also use event.target, if you are sure that your buttons don't contain other display objects, but currentTarget will always be safe in this case, because the event listener was added to the button itself. See my event flow tutorial for details):
var clipArray:Array = [home_mc, about_mc, products_mc, services_mc, contact_mc]; for (var i:int = 0; i < clipArray.length; i++) { clipArray[i].buttonMode = true; clipArray[i].addEventListener(MouseEvent.CLICK, clickHandler); } function clickHandler(event:MouseEvent):void { switch (event.currentTarget) { case home_mc : gotoAndStop("home"); break; case about_mc : gotoAndStop("about"); break; case products_mc : gotoAndStop("products"); break; case services_mc : gotoAndStop("services"); break; case contact_mc : gotoAndStop("contact"); break; } }
Notice that this switch statement uses the actual objects themselves, and compares them to event.currentTarget. I realize that you could also use strings, and compare them to event.currentTarget.name. Either way is fine, it's just that this way seems more direct and intuitive to me.
Still, this code is more verbose than it needs to be. Notice that there are two sets of information: the buttons themselves, and the destination frame on the main timeline that each button is intended to take you to. The buttons are already in an array, so why not put the destination frames in an array also? This technique is called using parallel arrays:
stop(); var clipArray:Array = [home_mc, about_mc, products_mc, services_mc, contact_mc]; var destArray:Array = ["home", "about", "products", "services", "contact"]; for (var i:int = 0; i < clipArray.length; i++) { clipArray[i].buttonMode = true; clipArray[i].addEventListener(MouseEvent.CLICK, clickHandler); } function clickHandler(event:MouseEvent):void { for (var i:int = 0; i < clipArray.length; i++) { if (event.currentTarget == clipArray[i]) { this.gotoAndStop(destArray[i]); } } }
Notice that each element of the first array has a corresponding, or parallel element in the other array. Now, when you click, there is another for loop inside the clickHandler that cycles through the clipArray and compares each button to the event.currentTarget. When it finds a match, it has effectively figured out which button was clicked. At that point, while we still have the proper value for "i," we can tell the main timeline to gotoAndStop() at the frame that's labelled with the value from the corresponding array.
Here's this simple website example, followed by a link for you to download the fla file:
Although the website example is simple, it makes a good illustration of the techniques outlined. So even if your buttons don't belong to a website application, the principles are the same. On the next page we'll explore how to give your buttons "disabling" behavior, using the same website example.