Another kind of drag and drop game that we might want to make is one in which we require the user to label something. In this variation, the items being dragged are still movie clips, but they typically contain words. The other big difference is that instead of the words snapping to the same x, y location as the matching clip, we might instead actually want the word to snap to a certain screen location that we determined ahead of time, because the x and y of the matching clip may not always be the best place to position the label, and usually won't be. We really want to be able to make it snap to any screen location we want in this type of game.
To author this, we might make word movie clips that say "Square", "Circle", and "Triangle" using static text boxes. These clips will also have their registration points in their center. What I usually do is make one symbol, and then right click it in the library and choose "duplicate," then just edit the resulting duplicate MovieClip symbols. Having made these symbols in the library, let's drag out an instance of each one, and give them instance names of square_word, circle_word, and triangle_word. These are the clips that we'll be dragging. Go ahead and delete the former set of drag clips from the stage (square, circle, and triangle), as these word clips will replace them. But keep the match clips (the ones at the bottom of the screen: squareMatch, circleMatch, and tirangleMatch).
Next, we need to do some pre-planning. In the Flash program, we drag the word clips to where we feel like they ought to wind up if they are dropped on their targets correctly. We make note of these positions, writing down the x and y locations of each one. These numbers can be found in the properties panel, of course. I came up with the following:

Here's what I jotted down on paper for my desired x, y (finishing) positions of the three word clips:
square_word:
x: 276
y: 207
circle_word:
x: 443
y: 207
triangle_word
x: 107
y: 207
Having made note of these locations, we can now move the label clips to arbitrary starting locations from which they will be dragged (and mix them up a bit). When the user drags one of these words, and correctly drops it on the correct matching clip, we will use these numbers as the x, y location to "snap" the word clip to.
Turning now to the code, we need to make just a few changes to make this work. The first change is to make the dragArray contain these new clips instead of the old ones we got rid of:
var dragArray = [square_word, circle_word, triangle_word];
The matchArray will stay the same, but now we need to add a new array which we will call posArray:
var posArray:Array = [ {x:276, y:207}, {x:443, y:207}, {x:107, y:207} ];
This array is an array of objects. In case you've never encountered this notation before, an object can be indicated using curly braces. Each object in the above line has an x property and a y property. Properties are noted just by naming them and putting a colon between the name and the value, and then commas to separate the name/value pairs. We have faithfully recorded the screen locations we wrote down. We have also made sure that they are in the correct order: square, circle, triangle. This comprises yet a third parallel array, and it's important to keep the items in it in the same order, just like we did for the dragArray and matchArray.
The next change is that the match clips need no longer have their alpha reduced. So we find the line that does that (line 12) and comment it out. This change isn't crucial, but it reflects the idea that this is a different kind of drag-drop game than the build one.
Finally, the last change is on lines 31 and 32. Rather than snapping the dragging clip to the same x and y as the matching clip, we instead snap it to the x and y of the corresponding element in our new posArray!
currentClip.x = posArray[index].x;
currentClip.y = posArray[index].y;
Notice that by creating an array of objects, we are able to use the name and index of the array, followed by a dot, then the name of the property we want that's stored there. Using arrays of objects can be an extremely useful technique, as this simple example demonstrates. We're only storing two properties in each object, but you could potentially store whatever information you want.
Here's the finished code:
var dragArray:Array = [square_word, circle_word, triangle_word];
var matchArray:Array = [squareMatch, circleMatch, triangleMatch];
var posArray:Array = [ {x:276, y:207}, {x:443, y:207}, {x:107, y:207} ];
var currentClip:MovieClip;
var startX:Number;
var startY:Number;
for(var i:int = 0; i < dragArray.length; i++) {
dragArray[i].buttonMode = true;
dragArray[i].addEventListener(MouseEvent.MOUSE_DOWN, item_onMouseDown);
//matchArray[i].alpha = 0.2;
}
function item_onMouseDown(event:MouseEvent):void {
currentClip = MovieClip(event.currentTarget);
startX = currentClip.x;
startY = currentClip.y;
addChild(currentClip); //bring to the front
currentClip.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, stage_onMouseUp);
}
function stage_onMouseUp(event:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_UP, stage_onMouseUp);
currentClip.stopDrag();
var index:int = dragArray.indexOf(currentClip);
var matchClip:MovieClip = MovieClip(matchArray[index]);
if(matchClip.hitTestPoint(currentClip.x, currentClip.y, true)) {
//a match was made! position the clip using the posArray values:
currentClip.x = posArray[index].x;
currentClip.y = posArray[index].y;
//make it not draggable anymore:
currentClip.removeEventListener(MouseEvent.MOUSE_DOWN, item_onMouseDown);
currentClip.buttonMode = false;
} else {
//match was not made, so send the clip back where it started:
currentClip.x = startX;
currentClip.y = startY;
}
}
And here's how the swf behaves:
On the next page, we'll make our drag-drop game routine into a cool reusable class!