Double click the Learn symbol in the library. Unlock the buttons layer if it's locked. Right click the first frame and choose "Copy Frames." Lock the layer. Next, double click the Drag symbol in the library. Add a layer above the bg layer. Right click the first frame and choose "Paste Frames." This will copy the buttons layer to this new symbol, and the buttons will retain their instance names, which were "learnBtn" and "dragBtn." They also retain their positioning, too, which saves us from having to do that work over again.
Before we do anything else, let's fix the navigation of our file. Let's turn our attention to the Drag.as file. Now we can progam these buttons, and we can even borrow and modify some code from the Learn.as file, and since these buttons have the same instance names, we only have to make a few changes. Here's the code copied from Learn.as (remember these lines?):
learnBtn.alpha = 0.5; dragBtn.buttonMode = true; dragBtn.addEventListener(MouseEvent.CLICK, dragBtnClicked);
And here's how we need to change them:
dragBtn.alpha = 0.5; learnBtn.buttonMode = true; learnBtn.addEventListener(MouseEvent.CLICK, learnBtnClicked);
Place them in the constructor function, right after the other things that are there. Next, we will copy this function from Learn.as:
private function dragBtnClicked(event:MouseEvent):void {
MovieClip(parent).gotoDrag();
}
Paste it into the Drag.as file, but modify it so that it reads:
private function learnBtnClicked(event:MouseEvent):void {
MovieClip(parent).gotoLearn();
}
Save the file, and test the movie. You should be able to fully navigate the program now, although the Drag screen is still blank except for the navigation buttons. But now you can go back and forth between the Learn and Drag screens.
Let's work on the drag screen some more. Add a new layer, call it "words." This is where we will create some movie clips with the names of the continents that the user can drag around the screen. When they are dropped on the correct continent, they will "snap" into place. I made some more static textboxes, typed in the name of a continent into each one, then converted each one to a MovieClip symbol. Then I gave each instance on the stage an instance name in the properties panel, using the same instance names I gave the continents, but with the suffix "_word" appended.
Next, let's do some more borrowing from the Learn screen. Double click the Learn screen in the library. Unlock the "continents" layer. Right click the first frame there and choose "Copy Frames." Lock the layer again. Double click the Drag symbol in the library. Add a layer to its timeline. Right click the first frame and choose "Paste Frames." Lock the layer. Lock every layer except the words layer. Drag the words layer to the top of the layer stack. What we need to do now is drag the words around the map and label the continents with them, then take note of each one's x and y position. These will be the positions to which the label clips will "snap" when they are dragged and dropped on the correct continent. What I usually do is make note of all these positions by writing them down on paper.

Having taken note of all the destination positions, you can now drag all the words back to the left side of the screen. Their start positions can just resemble a list, although you could actually mix them up and place them anywhere you want on the screen. This screen is now ready to program, so let's turn our attention back to the Drag.as file.

(Here you can see that the word clips have been arranged like a list on the left hand side of the screen).
In the Drag.as file, add these lines to the variables list:
private var wordArray:Array; private var matchArray:Array;
Add these lines to the end of the constructor function:
wordArray = [northAmerica_word, southAmerica_word, europe_word, africa_word, asia_word, australia_word]; matchArray = [northAmerica, southAmerica, europe, africa, asia, australia];
Next, we need to set up a for loop to add dragging behavior to each of the items in the wordArray. So add this to the end of the constructor, too:
for(var i:int = 0; i < wordArray.length; i++) {
wordArray[i].buttonMode = true;
wordArray[i].addEventListener(MouseEvent.MOUSE_DOWN, dragMe);
}
The next thing to do is write the dragMe function. Add this function to the end of the list of functions:
private function dragMe(event:MouseEvent):void {
event.currentTarget.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, dropMe);
}
Remember that event.currentTarget refers to whichever clip got the MOUSE_DOWN event. So this same listener will work for all of the clips. It will make whichever clip got the MOUSE_DOWN event to start dragging. However, when you program drag and drop, you need to add the MOUSE_UP event to the stage. This is to solve the following problem: If you add the MOUSE_UP event to the clip itself, someone might drag faster than the clip can keep up. If the mouse is released and the mouse pointer is not over the clip, you will be stuck in dragging mode. So we add the event listener to the stage instead. But solving this problem causes another one: When we write the handler for the stage, we can no longer use event.currentTarget to refer to the object being dragged. Why? Because event.currentTarget is going to refer to the stage, not the clip being dragged.
For this reason, I usually create a "blank" MovieClip variable to stand in for whatever clip is being dragged, and I usually call it currentClip. So add this line to the variables list:
private var currentClip:MovieClip;
Next, add a new line to the beginning of the dragMe function:
private function dragMe(event:MouseEvent):void {
currentClip = MovieClip(event.currentTarget);
event.currentTarget.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, dropMe);
}
Now, it just remains to write the dropMe function:
private function dropMe(event:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_UP, dropMe);
currentClip.stopDrag();
}
So the scenario goes like this: When a clip gets a MOUSE_DOWN event, the dragMe function runs. That function sets it as the currentClip and starts it dragging. It also adds an event listener to the stage to listen for MOUSE_UP. This event listener is the dropMe function. When the stage gets a MOUSE_UP event, the dropMe function runs, and that function removes the listener that called it, and then tells the currentClip to stop dragging.
Test the movie now. When you go to the drag screen, you will be able to drag and drop all the word movie clips. Now all we need to to is make our program determine if the word is being dropped onto the right continent. We can do this using the hitTestObject method of the MovieClip class. We also need to create another array to store the x and y values we wrote down earlier. Let's do that first. Add this line to the list of variables:
private var posArray:Array;
Then, in the constructor function, add this line:
posArray = [ {x:-264, y:-88}, {x:-186, y:44}, {x:12, y:-144}, {x:-5, y:-27}, {x:157, y:-144}, {x:258, y:86} ];
This may look scary at first if you are not familiar with it. This is an array of objects. This is a very powerful technique. The objects are declared just by using the curly braces. Using curly braces is like saying "new Object()." This array of six objects holds the destination positions of the word clips. Since it is a parallel array (just like the other two), every element needs to correspond to the same element in the other arrays.The properties stored can be accessed later with just the array name, an index in brackets, a dot, and the name of the property, so for example:
trace(posArray[0].x) // would trace out -264
So what we need to do, in the dropMe function, is determine the index of currentClip in the wordArray array, test to see if it is hitting the corresponding element in the matchArray, and if it is, position it at the x and y location in the posArray. Also, take away its dragging behavior. However, if it's dropped and it isn't hitting its matching clip, we need to send it back to where it started from.
To send it back to where it started from, we need to record its starting position when it first gets the MOUSE_DOWN event. So let's create a couple more variables for the class. Add these to the variables list:
private var startX:Number; private var startY:Number;
Add these lines right after the first line of the dragMe function:
startX = currentClip.x; startY = currentClip.y;
This will record the starting position of whatever clip is being dragged, so that if it doesn't match when it is dropped, it can be sent back to wherever it came from.
Now let's finish off the dropMe function. Add these lines after the other two lines that are already there:
var index:Number = wordArray.indexOf(currentClip);
if(currentClip.hitTestObject(matchArray[index])) {
currentClip.x = posArray[index].x;
currentClip.y = posArray[index].y;
currentClip.removeEventListener(MouseEvent.MOUSE_DOWN, dragMe);
currentClip.buttonMode = false;
} else {
currentClip.x = startX;
currentClip.y = startY;
}
This is similar to what we did before on the Learn screen. We set up a temporary variable, "index," then use the indexOf method to find out the index into the wordArray of currentClip. Once that is found out, we can use it on the other parallel arrays. currentClip is tested to see if it is hitting the corresponding object in the matchArray. If it is, the same index number is used to position it. Then the "dragMe" event listener is removed from currentClip so that it can't be dragged again, and its buttonMode is set to false so that it doesn't get the hand cursor any more. It's out of the game. But if it doesn't match, the else block comes into play, which sends the clip back to where it started.
Here's the final version of Drag.as:
package {
import flash.display.*;
import flash.events.*;
public class Drag extends MovieClip {
private var wordArray:Array;
private var matchArray:Array;
private var posArray:Array;
private var currentClip:MovieClip;
private var startX:Number;
private var startY:Number;
public function Drag() {
addEventListener(Event.ADDED_TO_STAGE, addedHandler);
addEventListener(Event.REMOVED_FROM_STAGE, removedHandler);
dragBtn.alpha = 0.5;
learnBtn.buttonMode = true;
learnBtn.addEventListener(MouseEvent.CLICK, learnBtnClicked);
wordArray = [northAmerica_word, southAmerica_word, europe_word, africa_word, asia_word, australia_word];
matchArray = [northAmerica, southAmerica, europe, africa, asia, australia];
posArray = [ {x:-264, y:-88}, {x:-186, y:44}, {x:12, y:-144}, {x:-5, y:-27}, {x:157, y:-144}, {x:258, y:86} ];
for(var i:int = 0; i < wordArray.length; i++) {
wordArray[i].buttonMode = true;
wordArray[i].addEventListener(MouseEvent.MOUSE_DOWN, dragMe);
}
}
private function addedHandler(event:Event):void {
this.x = stage.stageWidth / 2;
this.y = stage.stageHeight / 2;
}
private function removedHandler(event:Event):void {
}
private function learnBtnClicked(event:MouseEvent):void {
MovieClip(parent).gotoLearn();
}
private function dragMe(event:MouseEvent):void {
currentClip = MovieClip(event.currentTarget);
startX = currentClip.x;
startY = currentClip.y;
event.currentTarget.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, dropMe);
}
private function dropMe(event:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_UP, dropMe);
currentClip.stopDrag();
var index:Number = wordArray.indexOf(currentClip);
if(currentClip.hitTestObject(matchArray[index])) {
currentClip.x = posArray[index].x;
currentClip.y = posArray[index].y;
currentClip.removeEventListener(MouseEvent.MOUSE_DOWN, dragMe);
currentClip.buttonMode = false;
} else {
currentClip.x = startX;
currentClip.y = startY;
}
}
}
}
Save the file, test the movie, and you will see it in action. If you drag a name to where it belongs on the map, it will snap into position, and be deactivated. If you drag a name to anywhere it doesn't belong, it will snap back to where you dragged it from.