Enjoy hours of fun whacking the stars out of these cute little moles ... err ... snowmen.
History of Whack A Mole Game
Whack-a-mole was a game which took stage in arcade centres many years back. The player interacted with the game by taking a mallet and whacking little moles which popped out of some nine holes randomly.
Even though gaming has progressed by leaps and bounds today, the single-minded purpose of whacking any moles that pop up of the holes remains a strong and powerful fun factor. Arcade centres still have this game around, and I do still see people playing it. It just shows that games do not have to be overly complex to be fun.
Without infringing any copyright ... let's call this tutorial Whack a Snowman. =)
Some nine snowman (or snowmen?) pop up at random intervals, and the player must use the mallet to hit them down immediately. The player has 1 minute to hit as many snowman as accurately as he can.
The hammer follows the mouse cursor.
Click to swing the hammer and hit the snowman down.
Entire game stops after 1 minute.
Download the Game Files
The files you need to create this game can be downloaded from here.
Step 1 - Managing your FLA file
In this tutorial, we see how we can use a custom mouse cursor for our game rather than use the boring default cursor. It is appropriate in this tutorial to change it to the hammer cursor since that gives the player the feeling that he is really playing the real arcade version of it.
Only vector graphics are used here, so you'll find the RAW folder empty. There are only 3 movieclips used - GameStage, Hammer and Snowman.
The movieclips have a more complex frame structure this time round, so take a closer look. The labels used are important because they help to control the logic, so if you're doing this from scratch, make sure you get the labels right.
The frames labelled idle are the frames that show the hammer doing nothing. When the user is not clicking on the hammer to hit the snowman, the hammer should be within these frames. The frames that are labelled as "hitting" are the frames that will be played when the player clicks the mouse. It is an animation showing the hammer raised and dropped to hit something. After the "hitting" animation is played, it eventually loops back and stop at the "idle" frame.
The Snowman movieclip has a fairly complex frame structure as well. The frames labelled "popup" are the frames that will show the animation of the snowman raising itself. There is an actionscript right in frame 1 that stops the animation, so the default state of all snowman right at the start will be what you see in frame 1.
The frames labelled "up" is the animation that shows the snowman raised and standing up, waiting for the palyer to hit it. This labelling of the frames is tied to the logic as well. You'll see later that we only get a score when we click on a snowman that is currently in this frame of action.
"fall" frames depict the animation of the snowman dropping back onto the floor. Eventually, it loops right back to the start and stops at frame 1 again.
To handle the complexity of the Snowman, we'll be using an external .as file for it. You'll find it in Snowman.as under the Game package.
The game stage is also a little more complex here, as we added 2 new text fields to display to the user the number of misses, and the remaining time to play the game.
Make sure that they are named txtMiss and txtTimer accordingly.
Step 2 - Starting up the game in your GameController.as
Usually, we look immediately at the startGame function. But here, since we're going to be using a new custom mouse cursor for the game which is the hammer, let's do it immediately when the game starts. What better place than the constructor function to do this? Take a look at the GameController() constructor in GameController.as.
public function GameController()
//Change Cursor hereMouse.hide();
mouseCursor = new Hammer();
mouseCursor.mouseEnabled = false;
In line 44, Mouse.hide() is called to hide the default cursor. The player will not be able to see the arrow cursor moving around the screen. Line 45 then creates the hammer movieclip (we're using the default Flash class here since we did not define the Hammer class externally as a .as file). What line 46 does is to make the hammer, referenced henceforth by the variable mouseCursor, ignore all clicks on it. Because the hammer movieclip will be made to follow your mouse cursor later on, it is always under the mouse cursor position. Without line 46, it will trap all mouse click events and none of your clicks on the snowman will work.
In line 48, we addChild the mouseCursor to the root instead of mcGameStage because the mouse should be above all UI layers. Then we add an event listener to the mouseCursor, executing the function followMouse every ENTER_FRAME.
Let's take a look at what happens in the followMouse function.
You've seen what mouseX and mouseY do in the Tutorial 1. They basically return you the x and y position of the mouse currently. By teleporting the mouseCursor to these coordinates, what we're doing is actually making mouseCursor (which holds the Hammer movieclip) follow wherever the mouse is moving. To the player, he gets the illusion that he is in fact controlling the Hammer movieclip as his mouse.
With that out of the way, let's take a look at the startGame function.
public function startGame()
playerScore = C.PLAYER_START_SCORE;
playerMiss = C.PLAYER_START_MISS;
timer = C.PLAYER_START_TIMER;
snowmanList = new Array();
for (var i=0; i< 3; i++)
for (var j=0; j< 3 ; j++)
var newSnowman =
new Snowman(j * C.SNOWMAN_DISTANCE + C.SNOWMAN_START_X,
i * C.SNOWMAN_DISTANCE + C.SNOWMAN_START_Y);
Most of the code here are pretty self-explanatory. The entire game runs on a timer of 60 seconds, so the variable timer is assigned a value of 1800 (based on 30 fps, 60 seconds = 1800 ticks).
Lines 66 to 75 looks complex, but the double for loop is just creating and placing the snowman movieclips onto the proper positions on the game stage. Remember to push them into the snowmanList, the array that is used to hold all snowman movieclips, and to add them to the mcGameStage.
In line 78, we make the entire mcGameStage a big hit area by getting it to respond to mouse click events. So wherever the player clicks the mouse on the entire game stage, this function clickToHit will be called.
Step 3 - Key Handlers
There're no keyboard inputs to the game for this tutorial, so we can safely ignore adding any key handlers here. The only form of user input will be the mouse.
Step 4 - Game Loop - Handle System/Time
I'm going to add in another component to the game loop here. It's not really part of the user input, game logic or display, but it's useful nevertheless. What this component does is to handle timers, or check for pauses in the game, etc. I'll consider it as the administrative portion of the game loop. Therefore, it is placed right at the start of the game loop.
Since our game is running on a timer of 1 minute, the game must go into a gameOver state once it reaches the time limit. The variable timer here keeps track of the total amount of time. Once it reaches 0 or less than that, the gameOver function is called. The return syntax forces the function to exit out, and it just prevents the code from going any further down the game loop.
We'll take a look at the gameOver function later. For now, let's go further down the game loop to see what happens.
//Handle User Input
//Handle Game Logic
//******************//Check to bring up Snowmanif (Math.random() < C.SPAWN_SNOWMAN_CHANCE)
var randomSnowman = Math.floor(Math.random() * 9);
if (snowmanList[randomSnowman].currentLabel == C.SNOWMAN_POPUP)
There isn't any user input in this game except the mouse clicks, which we'll be handling in the function clickToHit. More on that later. In the portion of the code to handle the game logic, we set a random chance for the snowman to pop up as a constant in the file C.as. Line 105 checks if we should spawn the snowman up. If so, line 107 then checks which snowman should be popping up by generating a random number from 0 to 8. Since each of the snowman is already pushed into the snowmanList earlier on, we just need to access that particular index of the array to reference it.
Line 108 however makes an additional check to see if that chosen snowman is currently in its popped up state. This is done by checking its value in the property currentLabel.
As a refresher, if you refer to the diagram above, if the snowman is currently in frame 1, its value of currentLabel will be "popup". If it is currently in frame 10, its value of currentLabel will be "up".
To get the snowman to pop up, we just execute its function popUp() that is already defined in Snowman.as.You can see from the code pasted below that the popUp function just sets a popUpTimer in it and then gets the Snowman movieclip to go to and play the frame "popup".
public function popUp()
this.popUpTimer = C.SNOWMAN_TIME_UP;
Now, let's take a look at the later portion of the game loop.
Now, we need to update the snowman. Like before, this complex update function is now loaded in the external Snowman.as. This is something you have to start getting used to. So let's head over to snowman.as to see what is written in the update function.
public function update()
if (this.currentLabel == C.SNOWMAN_UP)
this.popUpTimer -= C.TIME_UP_DECREASE;
if (this.popUpTimer <= 0)
You can see that the entire update function runs when the snowman is currently at the frames with the label "up". If you refer to the fla file again, it's frames 7 to 12. It makes sense to only update those snowman which are popped up because we need to check when they should go back down. There isn't much interaction we need to do with those dormant snowman.
In line 42, we reduce the popUpTimer by the constant value TIME_UP_DECREASE. If we want to increase the level of difficulty by shortening the amount of time the player has to hit the snowman, then this is an area where we can work on. The TIME_UP_DECREASE value can be increased for such an effect.
Lines 44 to 51 control the behaviour when the snowman has reached the end of its lifespan and should go back down. We play the animation labelled "fail", which is essentially the animation of the snowman falling back down. If the snowman has been hit, the variable isHit should contain true (we set this under the function gotHit). Otherwise, if the snowman fell back down not because it got hit, then we execute this function increaseMiss.
This is a concept worth mentioning here. You see that this function increaseMiss is a little special here, because it is not actually a function of the Snowman class, but rather a function of the GameController class in GameController.as. This is a concept we'll see more often later on when these child class like Snowman, Bullet, or Enemy need to communicate back with the main GameController to update some system variables.
In this case, we needed to update the number of misses, which is stored in the playerMiss variable back in the GameController class. If you look at lines 161 to 165 in GameController.as, we've prepared this function for the child classes to use.
//public functions for children to invokepublic function increaseMiss()
playerMiss += 1;
You may also notice that we used MovieClip(root).increaseMiss(). Why can't we just use the code root.increaseMiss()? Well, basically you can, but this casting is used to bypass the strict warning systems that are built in. If you try root.increaseMiss(), you will get a warning from Flash that says "1061: Call to a possibly undefined method increaseMiss through a reference with static type flash.display:DisplayObject."
So either you make it clear to Flash that root is really a MovieClip by casting it, or you turn off the Warning under File > Publish Settings > ActionScript version Settings > Uncheck Warnings Mode.
I'll leave it to you to make the choice.
Let's carry on with the game loop. The other interesting function we should look at should be the clickToHit function, which is triggered by the player whenever he clicks on the mcGameStage.
private function clickToHit(evt:MouseEvent)
//Check if hammer hit the snowmanfor (var i=snowmanList.length - 1; i >= 0; i--)
playerScore += C.SNOWMAN_POINTS;
Right at the start in line 134, we play the animation of the whacking hammer.
Then we loop through each snowman to see whether the hammer is colliding with any of them. If it is, we take it that the hammer has hit the snowman. It's a little less than perfect here by simply using hitTestObject to check for collisions, so I admit that I'm taking the easy way out here. This is definitely an area we can further refine on.
Anyway, if the hit is made, then we execute the gotHit method for that particular snowman. The score is increased and since it makes sense that each swing can hit only 1 snowman, we add in a break statement there.
The gotHit method defined in the Snowman class reduces the popUpTimer to 0 immediately (so that the snowman will fall at the next update), and sets the isHit property to true.
We now have a few more things to update in the display portion besides just the score. The display for the number of misses is trivial, because the information is stored in the variable playerMiss and we just have to set it as the text for txtMiss.
There is a litte more logic involved in the timer because the timer stores the total number of ticks that the game is allowed to run for, which is 1800. Before displaying to the user, we need to divide this information by the value of 30 stored in the constant GAME_FPS. So the user sees 60 seconds right at the start of the game.
Step 7 - Game Over
private function gameOver()
Over at the gameOver function, we remove all the listeners, as well as set some of the variables used to null, so that the Garbage Collector can clean up the memory use.
I also enabled the mouse once again so that the player can see his default mouse cursor.
And here you have it ... the working game! If you like it ... share it!
Download the Game Files
The files you need to create this game can be downloaded from here.
How To Play
Objective: Quickly hit each Snowman as it pops up.
Controls: Move the hammer as your mouse cursor.
Sounds & Music
Game Development Resources
Posted by Silas
on 2014-11-01 19:59:33
I used a smartphone to go through this tutorial and I cant seem to find the link to the file you kept talking about
Posted by Jian Kai
on 2014-07-21 13:26:34
when i try working on the game, the timer,score as well as the miss keeps remaining on 0, does anyone know how to solve it ?
Posted by jm
on 2014-05-13 09:43:07
how do i change the hammer image and the snowman image to the image that i want?
Posted by Joseph
on 2012-12-19 23:58:57
@Shirley, you can always add in a variable to increase every time the player clicks on the mouse. If it hits, decrease that variable.
When that variable reaches a certain value, 3 in your case, then set timer to 0 immediately, or find a way to call the gameOver() method.
Posted by Shirley
on 2012-07-13 16:04:45
I'm a beginner in using flash~I saw the game that you create using flash,it is interesting^^ This game is one of the part of my course project, but it is slightly different in the game~If i don't want the timer, once the gamer miss 3 time it will immediately game over.<< How to modify the action script to become the game that i mentioned?
Posted by Yalung
on 2011-11-07 07:07:03
Thank you for your tutorials, I will start making games following your concepts and the workflow you use. I will give you a link back in my website, you explain everything very nice. Greetings from Venezuela!
Posted by Yalung
on 2011-11-06 15:09:57
Font embedding is possible since MX I think. Not quite sure. But was a little bit complicated to be done.
Posted by Nick
on 2011-07-25 00:27:47
Hi how do I put a restart button at the end to restart the game?
Posted by Joseph
on 2011-03-23 00:07:19
Not that they only work in CS4. But CS5 introduces this new concept of font embedding. For dynamic text to work, you either need to embed the fonts, or you can simply change the property to "Use Device Fonts". Select all the dynamic text fields in the game and go to the properties panel to change it.
That should work.
Posted by Rebecca
on 2011-03-22 06:56:43
I downloaded the files and the timers, score, and miss only work in CS4. Do you know what changes need to be made for CS5??