Whack a mole game in javascript

Learn how to create whack a mole game in javascript.

It is a simple game in which every time a mole comes out from the ground we have to whack it. You get point every time you successfully whack a mole.

Whack a mole javascript

By building this game you will learn

  • HTML:- How to position elements to give effect of something is coming up from underneath.
  • CSS:- Create elements with aspect ratio 1:1 that is equal height and width and how to overlay one over anthoer.
  • Javascript:- Randomly modify any elements at given intervals.

I have broken down the development in three different parts in which we will proceed to next after finishing the previous.

  1. Create the layout or skeleton of the game to show different ground.
  2. Design each area to show dirt and mole and how mole will appear.
  3. Show the moles in different ground at different interval and if it whacked that count the points.

I assume you now have good idea about what we are building and how we going to build it, so lets start the development.

HTML layout of whack a mole.

The layout is divided in basically two parts.

  1. An area where start button and score will be displayed.
  2. Play area where mole will popup from the ground.

The first part is pretty straight forward, we have to just define two elements, button and span to display the score.

The second will have different sections which will contain dirt and mole images. Dirt will be always visible and mole will popup.

This images are wrapped inside a wrapper to give spaces between two grounds.

The images will be added as background image to the elements so we will assign classes to add styles effectively.

You can dynamically generate the no of grounds, but here I am pre defining them.

<main>
    <section id="score-area">
        <button class="primary">Start</button>
        <span id="score">Score: <span>0</span></span>
    </section>

    <!-- Play area -->
    <section id="play-area">
        <section class="ground">
            <div class="wrapper">
            <div class="dirt"></div>
            <div class="mole"></div>
            </div>
        </section>
        <section class="ground">
            <div class="wrapper">
            <div class="dirt"></div>
            <div class="mole"></div>
            </div>
        </section>
        <section class="ground">
            <div class="wrapper">
            <div class="dirt"></div>
            <div class="mole"></div>
            </div>
        </section>
        <section class="ground">
            <div class="wrapper">
            <div class="dirt"></div>
            <div class="mole"></div>
            </div>
        </section>
        <section class="ground">
            <div class="wrapper">
            <div class="dirt"></div>
            <div class="mole"></div>
            </div>
        </section>
        <section class="ground">
            <div class="wrapper">
            <div class="dirt"></div>
            <div class="mole"></div>
            </div>
        </section>
        <section class="ground">
            <div class="wrapper">
            <div class="dirt"></div>
            <div class="mole"></div>
            </div>
        </section>
        <section class="ground">
            <div class="wrapper">
            <div class="dirt"></div>
            <div class="mole"></div>
            </div>
        </section>
    </section>
</main>

Styling the whack a mole game with CSS.

We will be using flexbox for aligning the elements.

Make sure you set the box-sizing:border-box to restrict dimension inside the element. You can read more about it on how box-model works in CSS.

Also I have set the main wrapper to the 55% of window width. You can keep it as per your requirement.

* {
  box-sizing: border-box;
}

main {
  width: 55%;
  margin: 0 auto;
}

Styling Score Area

The bottom and the score will be placed on the both the end of the main parent.

#score-area {
  display: flex;
  justify-content: space-between;
  padding: 0 20px;
  font-size: 30px;
}

button {
  position: relative;
  font-size: 14px;
  font-weight: 600;
  text-align: center;
  padding: 0.7em 1.2em;
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 46px;
  min-width: 96px;
  border-radius: 4px;
  background-color: #fff;
  border: 1px solid;
  color: #fff;
  -webkit-transition: background 0.2s ease;
  -moz-transition: background 0.2s ease;
  -o-transition: background 0.2s ease;
  transition: background 0.2s ease;
}

.primary {
  background-color: #2fcb53;
  border-color: #2fcb53;
  color: #fff;
}

.primary:hover {
  background-color: #48dd84;
  border-color: #48dd84;
}

Designing the ground

We are showing 4 grounds in a single row and each ground will be of 1:1 aspect ratio where width and height will be equal.

#play-area {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
}

.ground {
  display: inline-flex;
  flex: 1 1 25%;
  justify-content: center;
  align-items: center;
  padding: 10px;
}

.wrapper {
  position: relative;
  width: 100%;
  padding-bottom: 100%;
  overflow: hidden;
}

If you can see we have made the .wrapper relative positioned because mole will be placed inside it which will move up and down and adding padding-bottom: 100% is a simple hack to make the height same as width.

Creating the mole and dirt

Dirt and mole both will be added as background image and the element will be positioned absolute to the parent so that we can move them up and down creating the effect of things are popping up.

Dirt will be in the front of the mole to give the effect that mole appears from back of the dirt.

.dirt,
.mole {
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0;
  background-size: contain;
  background-repeat: no-repeat;
}

.dirt {
  background-image: url("./assets/dirt.png");
  z-index: 1;
  background-position: center 113%;
}

.mole {
  background-image: url(./assets/mole.png);
  transition: all 0.1s ease;
  top: 100%;
  background-position: bottom;
  background-size: 73%;
}

.ground.active .mole {
  top: 0;
}

When the current ground has active class then show the mole by bringing it to the top.

Adding life to whack a mole with javascript.

To show the mole in each different ground randomly, We will generate a random number between the number of grounds and add active class to that ground.

Before adding the active class we have to make sure that we remove this class from other grounds so that mole appears in only one ground.

  const grounds = document.querySelectorAll(".ground");
  const length = grounds.length;

  var interval = setInterval(() => {
    //Generate a random number
    const random = Math.floor(Math.random() * length);
    
    //Remove the active class from every ground
    grounds.forEach((e) => {
      e.classList.remove("active");
    });
    
    //Add the active class to random ground
    grounds[random].classList.add("active");
  }, 700);

The frequency of showing the mole can be changed as per once requirement.

To count the score every time a mole appears in the ground and we click on it we have to increase the points.

For this we will listen to the click event on each ground and after click we will check if the ground has active class which means mole has appeared then increase the score.

 const score = document.querySelector("#score > span");
  let count = 0;

  grounds.forEach((e) => {
    e.addEventListener("click", () => {
      //If ground has active class which means it has mole
      //So increase the count
      if (e.classList.contains("active")) {
        count++;
        score.innerHTML = count;
      }
    });
  });

Now I want to start this game only when start button is clicked, so lets wrap all these inside a function then invoke the function when start button is clicked.

window.addEventListener("load", () => {
  document.querySelector("button").addEventListener("click", () => {
    startGame();
  });
});

const startGame = () => {
  const grounds = document.querySelectorAll(".ground");
  const length = grounds.length;

  const score = document.querySelector("#score > span");
  let count = 0;

  grounds.forEach((e) => {
    e.addEventListener("click", () => {
      //If ground has active class which means it has mole
      //So increase the count
      if (e.classList.contains("active")) {
        count++;
        score.innerHTML = count;
      }
    });
  });

  var interval = setInterval(() => {
    //Generate a random number
    const random = Math.floor(Math.random() * length);

    //Remove the active class from every ground
    grounds.forEach((e) => {
      e.classList.remove("active");
    });

    //Add the active class to random ground
    grounds[random].classList.add("active");
  }, 700);
};

You have learned how to create a simple whack a mole game with javascript🎉🎉🎉✨.