Whack-A-Mole is a classic arcade-style game that combines speed and precision. The game is set in a grid of holes, and the objective is to “whack” or hit the moles that randomly pop up from these holes. In this article, we are going to create Whack-a-Mole using HTML, CSS and JavaScript.
Preview Image:
Prerequisites:
Approach:
-
Start by creating the HTML structure for your Whack-A-Mole game. Use semantic tags like
<header>
,<main>
, and include elements for game information (score, timer) and the game container with mole holes. - Style your game using CSS to create an appealing layout and you have to use this mole image.
- Use JavaScript to add interactivity to your Whack-A-Mole game.
- Select DOM elements and initialize game variables.
-
Implement core functions for mole appearance (
comeout
) and handling clicks (handleMoleClick
). - Create functions to start the game, initiating intervals, and updating UI elements. Implement the end game function, clearing intervals, and resetting the game state.
- Add event listeners to buttons, ensuring proper states (disabled/enabled).
HTML
<!DOCTYPE html> < html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport"
content = "width=device-width, initial-scale=1.0" >
< link rel = "stylesheet" href = "styles.css" >
< title >Whac-A-Mole</ title >
</ head >
< body >
< div class = "game-info" >
< div id = "score" >Score: 0</ div >
< div id = "timer" >Time: 60s</ div >
</ div >
< button id = "startButton" >Start Game</ button >
< button id = "endButton" disabled>End Game</ button >
< div class = "game-container" >
< div class = "hole" id = "hole1" ></ div >
< div class = "hole" id = "hole2" ></ div >
< div class = "hole" id = "hole3" ></ div >
< div class = "hole" id = "hole4" ></ div >
< div class = "hole" id = "hole5" ></ div >
< div class = "hole" id = "hole6" ></ div >
< div class = "hole" id = "hole7" ></ div >
< div class = "hole" id = "hole8" ></ div >
< div class = "hole" id = "hole9" ></ div >
</ div >
< script src = "script.js" ></ script >
</ body >
</ html >
|
CSS
body { background-color : rgb ( 255 , 228 , 196 );
display : flex;
flex- direction : column;
align-items: center ;
justify- content : center ;
} .game-info { display : flex;
flex- direction : column;
align-items: center ;
justify- content : center ;
margin : 20px ;
} #startButton { margin-bottom : 20px ;
padding : 10px ;
font-size : 16px ;
cursor : pointer ;
} #endButton { margin-bottom : 20px ;
padding : 10px ;
font-size : 16px ;
cursor : pointer ;
} .game-container { background-color : rgb ( 1 , 254 , 64 );
display : grid;
grid-template-columns: repeat ( 3 , 160px );
gap: 10px ;
border : 2px solid rgb ( 216 , 216 , 216 );
padding : 20px ;
border-radius: 10px ;
} .hole { height : 150px ;
background : rgb ( 19 , 55 , 139 );
border : 5px solid rgb ( 30 , 30 , 30 );
cursor : pointer ;
border-radius: 100px ;
} .mole { background- size : 150px ;
background-image : url (
} @media only screen and ( max-width : 600px ) {
.game-container {
width : 80% ;
gap: 10px ;
padding : 5% ;
grid-template-columns: repeat ( 3 , 38% );
}
.hole {
height : 50px ;
width : 50px ;
border-radius: 100px ;
}
.mole {
background- size : 50px ;
background-image : url (
}
} |
Javascript
document.addEventListener( "DOMContentLoaded" , function () {
const holes =
document.querySelectorAll( ".hole" );
const startButton =
document.getElementById( "startButton" );
const endButton =
document.getElementById( "endButton" );
const scoreDisplay =
document.getElementById( "score" );
const timerDisplay =
document.getElementById( "timer" );
let timer;
let score = 0;
let countdown;
let moleInterval;
// Set the initial state to game over
let gameOver = true ;
function comeout() {
holes.forEach(hole => {
hole.classList.remove( 'mole' );
hole.removeEventListener(
'click' , handleMoleClick);
});
let random = holes[Math.floor(Math.random() * 9)];
random.classList.add( 'mole' );
random.addEventListener( 'click' , handleMoleClick);
}
function handleMoleClick() {
if (!gameOver) {
score++;
scoreDisplay.textContent = `Score: ${score}`;
}
this .classList.remove( 'mole' );
}
function startGame() {
if (!gameOver) {
// Prevent starting the game
// again if it's already in progress
return ;
}
gameOver = false ;
score = 0;
scoreDisplay.textContent = `Score: ${score}`;
timer = 60;
timerDisplay.textContent = `Time: ${timer}s`;
startButton.disabled = true ;
endButton.disabled = false ;
countdown = setInterval(() => {
timer--;
timerDisplay.textContent = `Time: ${timer}s`;
if (timer <= 0) {
clearInterval(countdown);
gameOver = true ;
alert(`Game Over!\nYour final score: ${score}`);
startButton.disabled = false ;
endButton.disabled = true ;
}
}, 1000);
moleInterval = setInterval(() => {
if (!gameOver) comeout();
}, 1000);
console.log( "Game started" );
}
function endGame() {
clearInterval(countdown);
clearInterval(moleInterval);
gameOver = true ;
alert(`Game Ended!\nYour final score: ${score}`);
score = 0;
timer = 60;
scoreDisplay.textContent = `Score: ${score}`;
timerDisplay.textContent = `Time: ${timer}s`;
startButton.disabled = false ;
endButton.disabled = true ;
}
startButton.addEventListener( "click" , startGame);
endButton.addEventListener( "click" , endGame);
}); |
Output: