monkeyflash.com
June 14th, 2007 | Posted in Flash & ActionScript, Tutorials
Creating drag and drop functionality in Flash CS3 is quite different than in older versions if you’re using the new ActionScript 3.0. While still relatively straightforward, the code can be a little more intimidating to users who are less familiar with ActionScript programming. If you’re like me, you’re here to try to keep your knowledge up-to-date, so let’s learn how to create a simple ActionScript 3.0 drag and drop game step-by-step. Download the FLA and follow along with these steps.
Open dragdrop.fla and review its organization. There are five layers in the file – one containing the “pegs” that we will drag and drop, one for the “targets” that we will drop the shapes onto, and one for the wooden box image. The text layer and the actions layer are currently empty. The pegs and the targets are movieclip symbols saved in the library. Press CTRL-L to view the library.
In order to provide the user with some feedback, we will display a message when the shapes are dropped, indicating whether or not they were placed successfully. Click frame 1 of the text layer. Use the Text tool to draw a text box underneath the peg shapes. Type “Put the shapes away!” to give the box an initial message.
In the Properties inspector, change the text box to a Dynamic Text box using the drop down menu. Set the font to Arial bold, the font color to #990000, and the size to 18pt. Give the text box an instance name of “reply_txt“. Use the Selection tool to position the text box if necessary.
In order to determine which target we drop our shapes over, we need to name them. Click the bright green pentagon target on the stage, and in the Properties inspector, give it an instance name of “targetpentagon_mc“. Repeat the process, giving the other three green targets instance names of “targetsquare_mc“, “targettriangle_mc“, and “targetflower_mc“. Take special note of the lowercase values – this will be important later.
Click the red square peg on the stage and give it an instance name of “square_mc“. Repeat the process, giving the other three colored pegs instance names of “flower_mc“, “triangle_mc“, and “pentagon_mc“.
Why are the targets so small?
The targets are smaller than the holes on the toy to provide a little more accuracy. Smaller targets mean that the shape has to be more closely lined up to register as a match.
Since the appearance of bright green targets spoils the illusion of a child’s toy, we will make them transparent. Using the Selection tool, click the first green target. Then, holding down Shift on the keyboard, click to select the other three targets. In the Properties inspector, choose Alpha from the Color dropdown menu. Then set the Alpha value to 0, making the targets transparent.
Now it’s time to dive into the code. Since ActionScript 3.0 no longer uses onPress
and onRelease
events, we’ll need some new code to create the same effect.
We’ll write some ActionScript to allow us to drag and drop the square peg. Select frame 1 of the actions layer, and open the Actions panel by pressing F9. Type in the following actions:
square_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp); square_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt); function pickUp(event:MouseEvent):void { event.target.startDrag(true); } function dropIt(event:MouseEvent):void { event.target.stopDrag(); } square_mc.buttonMode = true;
This tells Flash to begin dragging the movie clip when the user presses the mouse button, and stop when the mouse is released. In ActionScript 3.0, this is created by setting an event listener for each event, MOUSE_DOWN
and MOUSE_UP
, and assigning event handler functions (here called pickUp
and dropIt
) to tell Flash what to do once the event is triggered. Within these event handlers, event.target
refers to the object that initiated this event, which in this case will be square_mc
. Using event.target
instead of naming the object specifically will let us reuse this code for all four pegs in a few steps. The “true” parameter of the startDrag
function causes the shape to be picked up from its center, which will make it easier to place later. To display the hand cursor when clicking movieclip symbols, we set the buttonMode
property to true. Press CTRL-Enter to test the movie, and try dragging the square.
Here is where we determine where we release the peg, and provide feedback. Add the following code just below event.target.startDrag(true);
reply_txt.text = "";
Adding this code inside the pickUp
event handler will force the text inside the dynamic text field to clear when we pick up the peg.
Add the following lines below event.target.stopDrag();
var myTargetName:String = "target" + event.target.name; var myTarget:DisplayObject = getChildByName(myTargetName); if (event.target.dropTarget != null && event.target.dropTarget.parent == myTarget){ reply_txt.text = "Good Job!"; } else { reply_txt.text = "Try Again!"; }
The first new line creates a text string from the word “target” plus the name of the peg we just dropped, creating a name that matches one of our targets, such as “targetsquare_mc
“. The next line looks through our document for an object with that name, and saves a reference to it in a variable called “myTarget
“. The if
statement checks to make sure that the dropTarget
, or the item that is under our shape when we release the mouse button, is not null
, or empty. It also checks to see if the dropTarget’s parent is our myTarget
. In other words, if we release square_mc
over the movie clip named “targetsquare_mc
“, we receive a positive reply. If the peg is released anywhere else, we will receive a negative reply.
Test the movie by pressing CTRL-Enter. Try clicking the square and dragging it over an incorrect hole in the toy. Now, try dropping it over the correct hole. Check your code and fix any errors you encounter.
Copy the event listener lines from the Actions panel and paste them three more times. Change each reference of square_mc
to flower_mc
, triangle_mc
, and pentagon_mc
, respectively. Do the same for the buttonMode
line for each of the pegs. Since the event handler functions use references to event.target
, there is no need to modify any other sections for it to work with all four pegs.
Press CRTL-Enter to test the movie. Try dragging each of the pegs into both incorrect and correct places on the toy. You should receive the correct messages each time.
Currently, if you drag the yellow triangle, it passes over the square, but underneath the pentagon and flower shapes. That’s because they were added to the Flash document in a specific order, and the newest objects end up on top in the stacking order. ActionScript 3.0 no longer uses depths when placing objects, as the z-index
is handled automatically. In order to change the item’s z-index, we’ll use the addChild()
method.
We want to set the peg’s depth higher each time we drag it so that it will drag above the others. Add the following code within the pickUp()
event handler, after the line reply_txt.text = "";
event.target.parent.addChild(event.target);
In this line of code, event.target.parent
refers to the main timeline. Using addChild(event.target)
essentially adds the currently selected peg to the stage at the top of the stacking order, creating the appearance that we’ve picked it up above the others. Press CTRL-Enter to test the movie. As you drag each piece, it should always remain on top of the others.
Once the user has placed a peg in the right hole, it is a good idea to “lock” it into place so that they can’t accidentally move it again. We’ll also make sure that the peg is perfectly positioned when it is released.
Once a peg is placed, the easiest way to ensure that we can’t move it again is to remove the event listeners, and set buttonMode
back to false to remove the hand cursor. Add the following code within the dropIt()
event handler, within the if
statement, immediately after the line, reply_txt.text="Good Job!";
event.target.removeEventListener(MouseEvent.MOUSE_DOWN, pickUp); event.target.removeEventListener(MouseEvent.MOUSE_UP, dropIt); event.target.buttonMode = false;
When a peg is placed over the correct target, the if
statement returns true
, and that peg will be locked and no longer dragable. Test the movie with CTRL-Enter and see for yourself.
We should also make sure that once a peg is placed, it fits perfectly over the target. Add the following code immediately under the code you just added:
event.target.x = myTarget.x; event.target.y = myTarget.y;
This will set the dropped peg’s x
and y
coordinates to match those of the target movie clip. Note that in ActionScript 3.0, x
and y
properties no longer have an underscore. Test the movie with CTRL-Enter.
Currently, if you drag and drop a peg to either the wrong place or an empty area of the screen, it just stays there until you drag it again, which can be a little confusing. Let’s make each peg snap back to its original spot if it’s placed incorrectly.
Since we’ll need this information within two event handlers, let’s set up a pair of variables. Add the following code to above all the rest in the Actions panel:
var startX:Number; var startY:Number;
This creates two variables, startX
and startY
, that will contain our starting position. For now, they’re empty. When we pick up the shape, we’ll record its coordinates. Add this next code within the pickUp()
event handler:
startX = event.target.x; startY = event.target.y;
Now that the starting position is recorded, we can use those values to reset the peg when we miss the target. Add the following code within the dropIt()
handler, within the else statement:
event.target.x = startX; event.target.y = startY;
This will reset the x
and y
properties to their original values, but only when we release the shape outside of its target. Test your movie with CTRL-Enter, and drag the square to an incorrect space. It should snap back to its starting position.
Let’s add a congratulatory message that tells the user that all pegs have been placed correctly. We’ll need to keep a count of each correct peg drop, and when the count reaches four, we’ll change the text message.
Since the counter will keep track of all four pegs, we will create a variable in the actions layer. Add the following code above all of the other code in the actions panel:
var counter:Number = 0;
We will add one to the counter variable each time we release a peg over the right target. Add the following line of code within the dropIt()
event handler, within the if statement:
counter++;
This will add one to the value of the counter variable when the square peg is placed correctly.
Add the following code within the dropIt()
event handler, making sure that it comes after the else
statement:
if(counter == 4){ reply_txt.text = "Congrats, you're finished!"; }
This checks the counter
variable’s value, and if it equals 4, it will change the text in the dynamic text field to read, “Congrats, you’re finished!”.
If you have JavaScript enabled, you will see the completed project here.
Here’s a look at the completed code.
var counter:Number = 0; var startX:Number; var startY:Number; square_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp); square_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt); triangle_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp); triangle_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt); flower_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp); flower_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt); pentagon_mc.addEventListener(MouseEvent.MOUSE_DOWN, pickUp); pentagon_mc.addEventListener(MouseEvent.MOUSE_UP, dropIt); function pickUp(event:MouseEvent):void { event.target.startDrag(true); reply_txt.text = ""; event.target.parent.addChild(event.target); startX = event.target.x; startY = event.target.y; } function dropIt(event:MouseEvent):void { event.target.stopDrag(); var myTargetName:String = "target" + event.target.name; var myTarget:DisplayObject = getChildByName(myTargetName); if (event.target.dropTarget != null && event.target.dropTarget.parent == myTarget){ reply_txt.text = "Good Job!"; event.target.removeEventListener(MouseEvent.MOUSE_DOWN, pickUp); event.target.removeEventListener(MouseEvent.MOUSE_UP, dropIt); event.target.buttonMode = false; event.target.x = myTarget.x; event.target.y = myTarget.y; counter++; } else { reply_txt.text = "Try Again!"; event.target.x = startX; event.target.y = startY; } if(counter == 4){ reply_txt.text = "Congrats, you're finished!"; } } square_mc.buttonMode = true; flower_mc.buttonMode = true; triangle_mc.buttonMode = true; pentagon_mc.buttonMode = true;