When learning to code, practicing by creating applications is extremely important. Early-stage learners often get discouraged by the complexity of it all. Creating games is a great way to practice coding for various reasons. Firstly, we’re familiar with the game rules, which removes some of the complexity from the process. Secondly, games are fun, making the coding process more engaging.
This blog assumes a basic knowledge of HTML, CSS, and JavaScript. It is targeted toward individuals who are learning to create web applications.
In this blog, we’ll develop a game of whack-a-mole in JavaScript. Here are the game requirements:
Here’s a preview of what we aim to create.
Note: Press the “Start” button to play the game. Once the game is over, you may press the “Play again” button to play again.
From the looks of the above preview, we need the following:
A heading element to display the current score and a time remaining indicator.
The cards on which a mole appears.
A container to hold the cards.
A “game over” overlay notification.
Here’s an HTML that fulfils all but the last requirement. We’ll get to the “Game over” notification later. Note that you wouldn’t see anything besides “Score: 0” in the output at this point because all of the div
elements have zero width and height by default.
Note: At any point in this blog, you may switch the tabs in the coding playground to view the output or the corresponding code. Feel free to fiddle with the code and see the effect on the output.
Within the body
element, we set up an h2
element and a span
element (line 9) to display the score. We set up a div
element with an id
of grid
(line 10). This serves as the container for the cells. Inside it, we have the div
elements corresponding to the 9 cells (lines 11–19). For consistent styling of all the cells, we set a class
of square
for each of these div
elements. We also assign each cell a unique id
so that we may conveniently access each cell individually in code.
Although we defined all the div
elements in the HTML, we couldn’t see them. Let’s rectify that, as shown below:
We start with a CSS reset to avoid browser-specific style inconsistencies on lines 1–5. We target all HTML elements with the *
selector as well as the ::after
and ::before
pseudo-selectors (lines 1–5). We set the margins and padding to 0
(lines 2–3). We also set the box-sizing
property to border-box
, so that the border thickness is included in the box sizes. It is important to note that we refer to the CSS file in the HTML file on line 6.
Why are the width
and height
properties for the div
element with the id
of grid
set to 322
pixels (line 8 and line 9)? An individual cell looks reasonable with a height and width of 100 pixels. With three cells in a row, we need a width
of at least 300 pixels. We don’t want the cells to be cramped into each other, so we’ll need some spacing between them horizontally. That’s why we have left an allowance of 22 pixels in the grid
width. The same argument goes for the height
.
In the preview, we see that the squares are separated from the edges of the green-shaded playing area. To achieve that, we give the element with an id
of grid
a padding
of 4
pixels on all sides (line 10). We also give it a greenish background color (line 11). We give it rounded edges with the border-radius
property (line 12) to match the look in the preview. We apply margin: 50px auto
(line 13) so that this element is spaced from the top by 50 pixels and is centered horizontally on the screen.
At this point, you’ll see “Score: 0” at the top-left of the page and a greenish box near the center of the page. The h2
element for the score is too close to the edge of the page, so we need to add some space above and to the left of it. Here’s how we can do it:
Now, let’s move on to styling the 9 cells. Let’s give them a width and a height of 100 pixels each. Here’s the code with updated CSS:
Since these cells all have a class of square
, we use the class selector, .square
(line 20), and set the width
and height
(lines 21–22). We gave the elements a border on line 23. To have rounded edges, we used the border-radius
property on line 24. To introduce some spacing between two rows of cells, we use the margin-bottom
property on line 25.
The output in the above coding playground looks nothing like what we want. The div
elements with a class of square
are just hanging vertically, one in each row, near the left edge of their parent div
. This is because the div
s are block elements, each starting on a new line by default.
There are several ways to fix that. One is to use CSS Flexbox. Here’s the modified style:
We set the parent element’s display
property to flex
(line 18). To make the cells wrap around to the next row, we set the flex-wrap
property to wrap
(line 19). Since the parent is 322 pixels wide, and each cell is 100 pixels wide, we get a wrap-around after three inner div
elements. We set the justify-content
property to space-between
(line 20) so that the inner div
elements are spaced evenly in a row. Now, the cells are laid out nicely in a 3x3 arrangement.
Can you modify the code in the above playground to turn the board into a 4 x 4 grid?
Cascading Style Sheets (CSS) is a document type and the associated scripting language that describes the presentation of HTML documents. Using the CSS language, you can control the look and feel of web pages by defining layout, text, and image properties to be applied in a wide array of contexts. This course is a comprehensive introduction to both writing and implementing CSS. Using the document hierarchy model, you’ll learn how to tailor web styles to specific areas. With your hierarchy defined, you’ll dive deep into CSS fundamentals, adding colors, text styles, and backgrounds to your web page. After you’ve defined these elements, you’ll use CSS to define layouts around pictures and text flow and completely control your web page’s look. You’ll wrap up by exploring the essential animation functions of CSS. By the end of this course, you’ll have functional mastery of Cascading Style Sheets and the CSS scripting language. You’ll be prepared to build professional web pages with your code.
To display the mole in a cell, we can put an img
element inside the div
element corresponding to that cell. For instance, the following playground shows the mole image in the first cell:
We add an img
element to the div
element (line 12 in the HTML). We add a CSS rule for the img
element (lines 34–36 in CSS) to set the image width to 90 percent of the parent’s width. The mole image is larger in size than the cells, so skipping this step would cause the mole image to overflow the cell. To vertically and horizontally center the image within the cell, we use Flexbox (line 29) and set the justify-content
and align-item
properties to the image’s container element to center
(lines 30–31).
At the moment, we have displayed the mole image in a fixed cell. Here’s how we can display it in a randomly picked cell:
Create an img
element for the mole.
Pick a cell number at random.
Select the DOM element corresponding to the randomly picked cell.
Add the img
element as a child to the above div
.
Let’s get to work:
We create a new img
element using the createElement()
method on line 2. We store the image URL in a variable on line 3. We set the src
attribute of the img
element using the setAttribute()
method on line 4. We pick an integer from 1–9 at random on line 8 using the Math.random()
and Math.floor()
methods. The call to Math.random()
method returns a positive fractional value less than 1. We multiply it with 9 and take the ceiling results in a positive integer value less than or equal to 9. This gives us a random integer that we can use to pick a cell.
We query for the DOM element with an id
attribute equal to this random integer on line 8, and select that object in the variable named cell
. Finally, we append the img
element as a child to cell
(line 9).
Switch to the “Output” tab in the above playground, and you’ll see the mole in a randomly picked cell. Click the “Run” button in the playground, and you’ll see it appear in another randomly picked cell, as the above code would run again.
The mole needs to disappear after some time. Let’s work on that.
We have the variable named cell
that holds the div
element in which we displayed the mole, so removing the mole from view is a matter of using cell.removeChild(cell.firstChild)
. How do we make that happen after a random amount of time? For that, we’ll need to use the setTimeout()
method with a randomly drawn duration as an argument. To draw a random interval, we may use the Math.random()
method, again. Let’s say we want the mole to stay on the screen for at least 800 milliseconds and as long as 3 seconds (or 3000 milliseconds). The statement, Math.floor(Math.random() * n)
, generates a random positive integer less than n. In other words, it generates a random integer between 800 + Math.floor(Math.random() * n)
, and that gives us a random integer between
Let’s put this in action:
We use this expression on line 11 to draw a random interval duration. We use the setTimeout()
method to fire the removeMole()
function when this timer expires. In removeMole()
, we use the cell
variable to remove the mole image from the DOM. Once you’ve read the code, go to the “Output” tab in the above playground and click the “Run” button. A mole will appear in a random cell and then disappear after a random interval. You may click the “Run” repeatedly to observe this in action.
The mole must be in one cell for some time, disappear, and then reappear in a random cell after a random period of time. Let’s implement that.
To do this, we need to call another function, say addMole()
, from the removeMole()
function after a random interval. This function will display the mole in another random cell and call the removeMole()
function after another random interval. So, we’ll have created a cycle like the following.
Here’s the implementation:
First, we modify the removeMole()
function. We generate a random integer to serve as the delay in milliseconds, after which the mole reappears (line 16). We call the setTimeout()
funciton to invoke the addMole()
function after that delay (line 17). We define the addMole()
function on lines 20–26. Lines 21–23 are similar to lines 6–9. We show the mole in a random cell. On line 24, we generate a random integer to serve as the duration for which the mole stays visible. On line 25, we use the setTimeout()
function to have the mole disappear through the call to the removeMole()
function. Now, the mole will appear, disappear, and reappear repeatedly.
You might have noticed a bit of redundancy in the code above. Lines 6–9 and lines 21–23 serve the same purpose. Let’s fix that now:
The player will try to click the mole to score points. So we'll now manage mouse clicks. We can either add the click
event listener on the img
element or the div
element that contains it. The difference is that the img
element occupies 90% of the width of the div
element.
If we add the listener to the
div
element, we favor the player because they have more area available to score on.
We can add that event listener to the addMole()
function while adding the img
element to the div
. The callback can call the removeMole()
function to get rid of the mole. Here’s an outline of what we need to do:
When we display a mole in a cell, we need to add a click
event listener to that cell.
To indicate a success, in the event listener, remove the mole from that cell.
On line 22, we add a mouse-click event listener to the div
element and set the hitit()
function as the callback. From there, we call the removeMole()
function. Now, when we whack the mole, it will disappear.
However, there’s an issue with the above code. We call the removeMole()
function if the player clicks on the mole. But, there’s a call to the removeMole()
function scheduled on a timeout (line 24). One of these will happen first—it’ll remove the mole. The second call to the removeMole()
function won’t find a mole to remove, and line 13 will throw an exception.
To fix this error, we can store the timer ID in a variable and use the clearTimeout()
function to cancel the scheduled call to the removeMole()
function before calling it on line 28. Here’s the updated code:
We define a variable to hold the timeout ID on line 3. On lines 16 and 25, we store the timer in the variable. Before calling the removeMole()
function from the hitit()
function, we call the clearTimeout()
function to cancel that timer.
We haven’t kept track of the score yet. So, let’s do that now.
Here’s an outline of what we need to do:
Declare a variable with an initial value of zero since that’s the initial score.
Extend our click event handler to increment the score once the user successfully hits a mole.
We define a variable to hold the score on line 4. We also define a variable to hold the object corresponding to the span
element to display the score (line 18). If the player successfully clicks the mole before it disappears, we update the score
variable in the hitit()
function on line 33. We display the updated score on line 34.
However, you might notice one problem with the game. We still get a score if we click a cell after the mole has disappeared. Why is that? It is because we registered hitit()
as the event listener to that div
element, and it is still registered as a callback. We need to remove the event listener once the mole disappears one way or the other.
All it takes is a cell.removeEventListener()
on line 18 when removing the mole. With that, the player doesn’t get erroneous scores on clicking the div
element after the mole has disappeared.
We need to give the user a 1-minute interval to play a game. For that, we’ll maintain a timer. Once that timer expires, we clear any scheduled callback, click handler, and display a message that the game is over.
Here’s an outline of what we need to do:
Define a variable to hold the time elapsed so far.
Update the above variable after a fixed interval.
When the above variable reaches its limit (minimum or maximum, depending on our approach), display an HTML element to indicate “Game over.”
To set a one-minute timer for the “game over,” we define a variable to hold the duration in milliseconds (line 15). We register a function, gameOver()
, to be called after this duration (line 16). In the gameOver()
function, we clear any timers that are scheduled to display or remove the mole (line 42). We remove the click
event listener that might be registered on one of the div
elements (line 43).
To display “Game over” on the screen, we create a div
element (line 45). We set it’s text to “Game over” (line 46). We add a class of gameover
to this div
element. We define this style in the CSS file on lines 38–47. To take the div
element out of the normal flow of a page and display it at a fixed position, we set its position
property to fixed
(line 39). But where do we want this fixed position to be? That must be specified as done on lines 40–41. We set the top
and left
properties to 50%
, i.e., center of the screen. But if the element’s top-left corner is at the center of the page, then it won’t appear centered on the page. To fix that, we translate the div
element 50% upwards and leftwards (line 42). We set the background color to black with an opacity of 80% (line 43). We set the text color to a contrasting white (line 44). We set the font size to 2rem
(line 45). Finally, we apply a padding
of 20 pixels on each side so that the text, “Game over,” is a bit displaced from each side.
Our game doesn’t give the player any feedback about the time remaining. Let’s fix that.
Here’s an outline of what we need to do:
Add necessary elements to the HTML to indicate the remaining time.
Style the above elements as necessary.
Define a variable to keep track of the time remaining.
Update the above variable after a fixed interval.
Update the HTML elements based on the value of the above variable.
First, we edit the HTML to introduce a new section on lines 9–14. This serves to encompass both the score and the progress bar neatly. We move the score elements (the div
and the span
) inside this section and add another div
element (lines 11–13). There’s another div
element nested inside it on line 12.
Why create this specific structure? We’ll give the outer div
element a red background color as well as a specific width, and the inner div
a green background color, as well as a width of 100%. So, initially, this progress bar will appear all green. Gradually, we’ll reduce the width of the inner div
element, revealing red background color from below. Eventually, the progress bar will become all red when the game is over.
On to CSS. First, we eliminate the styling we applied to the h2
element. Then, we give the top
class a height
of 50 pixels and a width
of a hundred percent (lines 46–47). We set its display
property to flex
(line 48) so that we can use Flexbox to position its contents. We select even spacing for its content placement (line 49). We also go for vertically centered content (line 50). We then style the progress
class with a red background color (line 54). We give it a width
of 200 pixels (line 55) and a height
of 10 pixels (line 56). To get rounded corners for a cooler look, we give it a border-radius
of 10 pixels (line 57). For the remaining
class, we use a green background color (line 61), width
and height
of 100%
(lines 62–63), and a border-radius
of 10 pixels.
With just the above changes, the progress bar would turn up all green and stay that way. On to the code now.
We don’t need the 60-second timer anymore. We’ll update the progress
variable every second. Once it reaches 60 seconds, we’ll call the gameOver()
function. So, we get rid of the call to the setInterval()
function with the duration of 60000
milliseconds. We define a variable named progress
on line 16, initialized to 6000
. We set it equal to the value of duration
so that the progress bar appears 100% green initially. We want the progress bar to be updated every second, so we call the setInterval()
function to invoke the update()
function every second (line 17). We acquire an object corresponding to the progress div
on line 19 to adjust it with code.
We define the update()
function on lines 58–65. Since the progress
variable started at 6000 and needs to go down to 0 after a decrement every second, the decrement amount must be 1000. That’s what we’re doing on line 59. We update the percentage width of the progress div
on line 60. Finally, if the progress
variable reaches 0
, we clear the event that triggers every second to update the progress bar (line 62) and call the gameOver()
function.
Another improvement in the above code is giving the player feedback that they successfully hit the mole. We do this in the click
event handler on lines 41–42. We change the background color of a lighter shade (line 41) and then reset it to its previous value (line 42).
This course shows you how to build front-end web applications with plain JavaScript without using any (third-party) framework or library. It follows a "learning by doing" approach, which means that you don't have to read lots of text about the intricacies of JavaScript. Instead, you’ll focus on the essential parts of JavaScript and read only the minimum needed to start coding your first app. Learning from the examples provided in the course can quickly improve your understanding of basic concepts and techniques. By working your way through the code of these example apps and using it as a starting point for your projects, you’ll learn best practices and experience the joy of building something that really works and that you fully understand.
That concludes our development of the whack-a-mole game in JavaScript. We hope you enjoyed the experience. Keep learning by extending the game’s functionality and improving its styling. Experiment with making it responsive and mobile-friendly. Also try adding the “Play again” functionality that is available in the preview at the beginning of this blog.
Free Resources