VCB-324 Rich Media 2
Matching Game (Flash AS3)
Introduction
A common activity in Flash-based interactives is dragging an object to a target area in order to trigger a specific effect. The sample to the right is a simple match game; must must drag the circles to the matching rings. Note how the solid circles snap in place if you release them within their rings. The "Done" button checks your accuracy—if all three circles in the proper place, you get a smiley face; otherwise you get a frowny face.
The keys to accomplishing this are the use of conditionals and a "hit test," which is a method that Flash uses to determine whether two objects are in contact with one another.
Assignment
Use Flash to create a simply matching game. Instead of plain circles, think of a more interesting theme or use. The more unique and/or challenging the better.
Part One: Layout
- Open a new Flash file and save it as yourName_matchGame.fla.
- Create three different objects. They could be different colored shapes as I have in the example, or something more elaborate (like puzzle pieces).
- Convert each shape into a movie clip. Give them the instance names item1_mc, item2_mc, and item3_mc. Important: make sure you center the registration for each clip.
- Now make three target objects, like the colored rings above. Once again, center the registration. Important: the centers need to have a fill color like white; don't leave them empty.
- Covert each target object into a movie clip as well. Give them the instance names dropZone1_mc, dropZone2_mc, and dropZone3_mc.
- Mix up the arrangement of the three dragable objects (and/or target objects).
- Create two buttons: a "Done" button and a "Reset" button. Place them on stage. Give them the instance names "done_btn" and "reset_btn."
- Create a positive feedback movie clip and a negative feedback movie clip. In other words, something that suggests "Yay you got them right" and "Loser you got it wrong!" In my sample above I made a smiley face and a frowny face. Place both movie clips on your stage and give them instance names like "right_mc" and "wrong_mc." Don't worry that they're visible right now, we'll hide them later with Actionscript.
Part Two: Actionscript
- Create a new actions layer. In frame 1 of the actions layer add the following script:
This will hide the feedback objects until needed. It also assumes that you named your feedback movie clips right_mc and wrong_mc. If you used different instance names, change the script to reflect the names you used.
right_mc.visible=false; wrong_mc.visible=false;
- Now we need to define a few more variables:
var orig1X:Number=item1_mc.x; var orig1Y:Number=item1_mc.y; var orig2X:Number=item2_mc.x; var orig2Y:Number=item2_mc.y; var orig3X:Number=item3_mc.x; var orig3Y:Number=item3_mc.y;
Note that we have three sets of variables; each pair is storing the starting x and y position of its corresponding dragable object. This way, we'll be able to send the objects back to where they started should the player miss the target (creating a "snap-back" effect) and this will also allow us to reset the game at the end.
- Next we need to add listeners to the dragable objects in order to allow the users to click and drag them. While we're at it, we'll add listeners for the 'done' and 'reset' buttons too:
item1_mc.addEventListener(MouseEvent.MOUSE_DOWN, dragTheObject); item1_mc.addEventListener(MouseEvent.MOUSE_UP, item1Release); item2_mc.addEventListener(MouseEvent.MOUSE_DOWN, dragTheObject); item2_mc.addEventListener(MouseEvent.MOUSE_UP, item2Release); item3_mc.addEventListener(MouseEvent.MOUSE_DOWN, dragTheObject); item3_mc.addEventListener(MouseEvent.MOUSE_UP, item3Release); done_btn.addEventListener(MouseEvent.CLICK, checkAnswers); reset_btn.addEventListener(MouseEvent.CLICK, reset);
- It would be nice if the mouse pointer changes into a little pointing hand when it passes over the dragable objects to let the user know they're clickable. To do this we give the movie clips a button mode:
item1_mc.buttonMode=true; item2_mc.buttonMode=true; item3_mc.buttonMode=true;
- Now we need to start writing the functions that the listeners above are calling. Note that all 3 dragable objects call a function named "dragTheObject" when clicked; let's write that one first:
This function does three things. First, it creates a variable called "item" and then associates it with the object clicked-on (the "target'); so while the function is running, we can refer to the selected object as "item." Second, the function causes "item" to become dragable. Third, it counts the number of objects on stage (the "children" of the timeline) and then uses the setChildIndex method to move the dragable object to the top of the stack. This way the object will always be visible when dragged across other objects.
function dragTheObject(event:MouseEvent):void { var item:MovieClip=MovieClip(event.target); item.startDrag(); var topPos:uint=this.numChildren-1; this.setChildIndex(item, topPos); } - So what happens when the mouse button is released? Note that each object calls its own specific function on mouseUp. Each of these functions is very similar; in fact the only real difference is the "snap-back" location, that is the spot the object returns to on release.
These functions accomplishes several things. First they stop the dragging function for the current item. Next they check to see if item is centered over the appropriate drop zone object by using a hitTestPoint method. If it is, it snaps to the drop zone's center. If not, it jumps back to its starting location (like orig1X & orig1Y).
function item1Release(event:MouseEvent):void { var item:MovieClip=MovieClip(event.target); item.stopDrag(); if (dropZone1_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone1_mc.x; item.y=dropZone1_mc.y; } else { item.x=orig1X; item.y=orig1Y; } }; function item2Release(event:MouseEvent):void { var item:MovieClip=MovieClip(event.target); item.stopDrag(); if (dropZone2_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone2_mc.x; item.y=dropZone2_mc.y; } else { item.x=orig2X; item.y=orig2Y; } }; function item3Release(event:MouseEvent):void { var item:MovieClip=MovieClip(event.target); item.stopDrag(); if (dropZone3_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone3_mc.x; item.y=dropZone3_mc.y; } else { item.x=orig3X; item.y=orig3Y; } }; - Now we need to write the function that will check to see if the user got all three matches right when the "done" button is pressed:
function checkAnswers(event:MouseEvent):void { if (dropZone1_mc.hitTestPoint(item1_mc.x,item1_mc.y) && dropZone2_mc.hitTestPoint(item2_mc.x,item2_mc.y) &&
dropZone3_mc.hitTestPoint(item3_mc.x,item3_mc.y)) { wrong_mc.visible = false; right_mc.visible = true; } else { wrong_mc.visible = true; right_mc.visible = false; } }This function uses a group of hit tests to see of the three dragable objects are in their drop zones. If they are all in place, the right_mc is made visible. Otherwise the wrong_mc appears.
- Finally, the "reset" function:
This script hides both right_mc and wrong_mc, and then moves the items back to their starting positions.
function reset(event:MouseEvent):void { item1_mc.x=orig1X; item1_mc.y=orig1Y; item2_mc.x=orig2X; item2_mc.y=orig2Y; item3_mc.x=orig3X; item3_mc.y=orig3Y; right_mc.visible=false; wrong_mc.visible=false; }
Theme and Variations
- Eliminating the snap-back. What if you don't want the objects to return to their starting positions every time they're released? What if you want them to stay put? Eliminate the "else" portion of the 'itemRelease' functions found in step 6. You could comment them out or delete them altogether (note that you will have to repeat this for each of your itemRelease functions, not just the one shown below):
function item1Release(event:MouseEvent):void { var item:MovieClip=MovieClip(event.target); item.stopDrag(); if (dropZone1_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone1_mc.x; item.y=dropZone1_mc.y; /* } else { item.x=orig1X; item.y=orig1Y; */ } }; - Possible wrong answers. Maybe you would like to set it up so that it is possible to drag and drop an object on the wrong target to make the game a little harder. In this case one would have to press the "Done" button in order to determine if he/she had the right answer(s). There are a couple of ways yo can do this. One is to add two new conditionals to each function (existing code is shown in gray, new code is in black):
function item1Release(event:MouseEvent):void { var item:MovieClip=MovieClip(event.target); item.stopDrag(); if (dropZone1_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone1_mc.x; item.y=dropZone1_mc.y; } else if (dropZone2_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone2_mc.x; item.y=dropZone2_mc.y; } else if (dropZone3_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone3_mc.x; item.y=dropZone3_mc.y; } else { item.x=orig1X; item.y=orig1Y; } }; function item2Release(event:MouseEvent):void { var item:MovieClip=MovieClip(event.target); item.stopDrag(); if (dropZone2_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone2_mc.x; item.y=dropZone2_mc.y; } else if (dropZone1_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone1_mc.x; item.y=dropZone1_mc.y; } else if (dropZone3_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone3_mc.x; item.y=dropZone3_mc.y; } else { item.x=orig2X; item.y=orig2Y; } }; function item3Release(event:MouseEvent):void { var item:MovieClip=MovieClip(event.target); item.stopDrag(); if (dropZone3_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone3_mc.x; item.y=dropZone3_mc.y; } else if (dropZone1_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone1_mc.x; item.y=dropZone1_mc.y; } else if (dropZone2_mc.hitTestPoint(item.x,item.y)) { item.x=dropZone2_mc.x; item.y=dropZone2_mc.y; } else { item.x=orig3X; item.y=orig3Y; } };A more streamlined solution is to roll the three itemRelease functions into a single one:
You'll also have to change the item listeners so they call the newfunction itemRelease(event:MouseEvent):void { var thisItem:MovieClip = MovieClip(event.target); thisItem.stopDrag(); if (dropZone1_mc.hitTestPoint(thisItem.x,thisItem.y)) { thisItem.x = dropZone1_mc.x; thisItem.y = dropZone1_mc.y; } else if (dropZone2_mc.hitTestPoint(thisItem.x,thisItem.y)) { thisItem.x = dropZone2_mc.x; thisItem.y = dropZone2_mc.y; } else if (dropZone3_mc.hitTestPoint(thisItem.x,thisItem.y)) { thisItem.x = dropZone3_mc.x; thisItem.y = dropZone3_mc.y; } // to eliminate snap-back comment out the next three else statements: else if (thisItem==item1_mc) { event.target.x = orig1X; event.target.y = orig1Y; } else if (thisItem==item2_mc) { event.target.x = orig2X; event.target.y = orig2Y; } else { event.target.x = orig3X; event.target.y = orig3Y; } };itemRelease()function and not the individualitemRelease1(), itemRelease1(), anditemRelease1(). - Invisible drop zones. Sometimes you may want the target area for a dragable area to remain hidden. For example, in the piece to the right, the puzzle pieces snap to invisible drop zones. To create an invisible drop zone simply create a shape filled with white (or your chosen background color) and convert it to a movie clip. It's best to use the version that does not snap to wrong answers (so use the individual
itemRealease1(), itemRelease2()etc.functions as opposed to the combined function). - Sound effects. Adding a little sound to a game can really help bring it to life and make it seem more engaging. Here are some sounds you can use. Sounds should be imported to the library and then the property of each should be set to export for Actionscript. I'd recommend giving your sounds simple identifiers like "boing," "buzz," and "bell." Then in your actionscript create instances of each sound early in the script (where you declare all of your variables is a good place).
Then add a
var myBoing:boing = new boing(); var myBuzz:buzz = new buzz();
var myBell:bell = new bell();play()wherever you want a particular sound to occur. For example, add the "boing" to theonRelease()function.Similarly, you could add sounds to thefunction itemRelease(event:MouseEvent):void { var thisItem:MovieClip = MovieClip(event.target); thisItem.stopDrag(); myBoing.play();checkAnswers()function or any other function.function checkAnswers(event:MouseEvent):void { if (dropZone1_mc.hitTestPoint(item1.x,item1.y) && dropZone2_mc.hitTestPoint(item2.x,item2.y) &&
dropZone3_mc.hitTestPoint(item3.x,item3.y)) { wrong_mc.visible = false; right_mc.visible = true; myBell.play(); } else { wrong_mc.visible = true; right_mc.visible = false;
myBuzz.play(); } }
Your Turn
Now take these principes and develop your own game using something more interesting than circles.
Grading rubric
| 19–20 pts | A | Took principles and created something very original |
| 16–18 pts | B | Customized the graphics and/or code |
| 14–15 pts | C | Did the basics; it works, but it's nothing fancy. |
| 12-13 pts | D | Something's not working right. |
| 0-11 pts | F | Poor showing; mostly incomplete or full of errors. |
