Whack-a-Mole Game Using JavaScript

Whack-a-Mole is a popular arcade game where players use a mallet to hit mechanical moles that randomly pop up from holes in the game console. The objective is to hit as many moles as possible within a set time limit, earning points for each successful hit. The game requires quick reflexes and hand-eye coordination. There are also digital and handheld versions of the game available, extending its popularity beyond physical arcades. In this blog you will get to know how to create whack-a-mole game using JavaScript.

Whack-a-Mole Game Online

Score: 0
High Score: 0
Time Left: 30s
Mode: Easy

Prerequisites for playing Whack-A-Mole

  1. Quick Reflexes: The game involves rapidly hitting moles as they pop up, so players need fast reaction times.
  2. Hand-Eye Coordination: Players must be able to quickly and accurately move the mallet to the popping moles.
  3. Basic Understanding of the Game Rules: Knowing that the goal is to hit the moles and earn points, with more points typically awarded for faster and more accurate hits.

GitHub Repository

Learn how to create this Simple Game using HTML, CSS and JavaScript. Check out the Code below or visit the GitHub Repository by clicking the below button.

Whack-a-Mole Game Using JavaScript (Requirements)

HTML Code:

				
					<body>
    <div class="game">
        <div class="header">
            <h1>Whack-a-Mole Game</h1>
        </div>
        <div class="info-container">
            <div class="info-item">Score: <span id="score">0</span></div>
            <div class="info-item">High Score: <span id="highScore">0</span></div>
        </div>
        <div class="info-container">
            <div class="info-item">Time Left: <span id="timeLeft">30</span>s</div>
            <div class="info-item">Mode: <span id="mode">Easy</span></div>
        </div>
        <div class="mode-selection">
            <label for="modeSelect">Select Mode:</label>
            <select id="modeSelect">
                <option value="easy">Easy</option>
                <option value="medium">Medium</option>
                <option value="hard">Hard</option>
            </select>
        </div>
        <div class="mole-container">
            <div class="hole" id="hole1"><div class="mole" id="mole1"></div></div>
            <div class="hole" id="hole2"><div class="mole" id="mole2"></div></div>
            <div class="hole" id="hole3"><div class="mole" id="mole3"></div></div>
            <div class="hole" id="hole4"><div class="mole" id="mole4"></div></div>
            <div class="hole" id="hole5"><div class="mole" id="mole5"></div></div>
            <div class="hole" id="hole6"><div class="mole" id="mole6"></div></div>
            <div class="hole" id="hole7"><div class="mole" id="mole7"></div></div>
            <div class="hole" id="hole8"><div class="mole" id="mole8"></div></div>
            <div class="hole" id="hole9"><div class="mole" id="mole9"></div></div>
        </div>
        <button id="startButton">Start Game</button>
    </div> <script data-no-optimize="1">!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).LazyLoad=e()}(this,function(){"use strict";function e(){return(e=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n,a=arguments[e];for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(t[n]=a[n])}return t}).apply(this,arguments)}function i(t){return e({},it,t)}function o(t,e){var n,a="LazyLoad::Initialized",i=new t(e);try{n=new CustomEvent(a,{detail:{instance:i}})}catch(t){(n=document.createEvent("CustomEvent")).initCustomEvent(a,!1,!1,{instance:i})}window.dispatchEvent(n)}function l(t,e){return t.getAttribute(gt+e)}function c(t){return l(t,bt)}function s(t,e){return function(t,e,n){e=gt+e;null!==n?t.setAttribute(e,n):t.removeAttribute(e)}(t,bt,e)}function r(t){return s(t,null),0}function u(t){return null===c(t)}function d(t){return c(t)===vt}function f(t,e,n,a){t&&(void 0===a?void 0===n?t(e):t(e,n):t(e,n,a))}function _(t,e){nt?t.classList.add(e):t.className+=(t.className?" ":"")+e}function v(t,e){nt?t.classList.remove(e):t.className=t.className.replace(new RegExp("(^|\\s+)"+e+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")}function g(t){return t.llTempImage}function b(t,e){!e||(e=e._observer)&&e.unobserve(t)}function p(t,e){t&&(t.loadingCount+=e)}function h(t,e){t&&(t.toLoadCount=e)}function n(t){for(var e,n=[],a=0;e=t.children[a];a+=1)"SOURCE"===e.tagName&&n.push(e);return n}function m(t,e){(t=t.parentNode)&&"PICTURE"===t.tagName&&n(t).forEach(e)}function a(t,e){n(t).forEach(e)}function E(t){return!!t[st]}function I(t){return t[st]}function y(t){return delete t[st]}function A(e,t){var n;E(e)||(n={},t.forEach(function(t){n[t]=e.getAttribute(t)}),e[st]=n)}function k(a,t){var i;E(a)&&(i=I(a),t.forEach(function(t){var e,n;e=a,(t=i[n=t])?e.setAttribute(n,t):e.removeAttribute(n)}))}function L(t,e,n){_(t,e.class_loading),s(t,ut),n&&(p(n,1),f(e.callback_loading,t,n))}function w(t,e,n){n&&t.setAttribute(e,n)}function x(t,e){w(t,ct,l(t,e.data_sizes)),w(t,rt,l(t,e.data_srcset)),w(t,ot,l(t,e.data_src))}function O(t,e,n){var a=l(t,e.data_bg_multi),i=l(t,e.data_bg_multi_hidpi);(a=at&&i?i:a)&&(t.style.backgroundImage=a,n=n,_(t=t,(e=e).class_applied),s(t,ft),n&&(e.unobserve_completed&&b(t,e),f(e.callback_applied,t,n)))}function N(t,e){!e||0<e.loadingCount||0<e.toLoadCount||f(t.callback_finish,e)}function C(t,e,n){t.addEventListener(e,n),t.llEvLisnrs[e]=n}function M(t){return!!t.llEvLisnrs}function z(t){if(M(t)){var e,n,a=t.llEvLisnrs;for(e in a){var i=a[e];n=e,i=i,t.removeEventListener(n,i)}delete t.llEvLisnrs}}function R(t,e,n){var a;delete t.llTempImage,p(n,-1),(a=n)&&--a.toLoadCount,v(t,e.class_loading),e.unobserve_completed&&b(t,n)}function T(o,r,c){var l=g(o)||o;M(l)||function(t,e,n){M(t)||(t.llEvLisnrs={});var a="VIDEO"===t.tagName?"loadeddata":"load";C(t,a,e),C(t,"error",n)}(l,function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_loaded),s(e,dt),f(n.callback_loaded,e,a),i||N(n,a),z(l)},function(t){var e,n,a,i;n=r,a=c,i=d(e=o),R(e,n,a),_(e,n.class_error),s(e,_t),f(n.callback_error,e,a),i||N(n,a),z(l)})}function G(t,e,n){var a,i,o,r,c;t.llTempImage=document.createElement("IMG"),T(t,e,n),E(c=t)||(c[st]={backgroundImage:c.style.backgroundImage}),o=n,r=l(a=t,(i=e).data_bg),c=l(a,i.data_bg_hidpi),(r=at&&c?c:r)&&(a.style.backgroundImage='url("'.concat(r,'")'),g(a).setAttribute(ot,r),L(a,i,o)),O(t,e,n)}function D(t,e,n){var a;T(t,e,n),a=e,e=n,(t=It[(n=t).tagName])&&(t(n,a),L(n,a,e))}function V(t,e,n){var a;a=t,(-1<yt.indexOf(a.tagName)?D:G)(t,e,n)}function F(t,e,n){var a;t.setAttribute("loading","lazy"),T(t,e,n),a=e,(e=It[(n=t).tagName])&&e(n,a),s(t,vt)}function j(t){t.removeAttribute(ot),t.removeAttribute(rt),t.removeAttribute(ct)}function P(t){m(t,function(t){k(t,Et)}),k(t,Et)}function S(t){var e;(e=At[t.tagName])?e(t):E(e=t)&&(t=I(e),e.style.backgroundImage=t.backgroundImage)}function U(t,e){var n;S(t),n=e,u(e=t)||d(e)||(v(e,n.class_entered),v(e,n.class_exited),v(e,n.class_applied),v(e,n.class_loading),v(e,n.class_loaded),v(e,n.class_error)),r(t),y(t)}function $(t,e,n,a){var i;n.cancel_on_exit&&(c(t)!==ut||"IMG"===t.tagName&&(z(t),m(i=t,function(t){j(t)}),j(i),P(t),v(t,n.class_loading),p(a,-1),r(t),f(n.callback_cancel,t,e,a)))}function q(t,e,n,a){var i,o,r=(o=t,0<=pt.indexOf(c(o)));s(t,"entered"),_(t,n.class_entered),v(t,n.class_exited),i=t,o=a,n.unobserve_entered&&b(i,o),f(n.callback_enter,t,e,a),r||V(t,n,a)}function H(t){return t.use_native&&"loading"in HTMLImageElement.prototype}function B(t,i,o){t.forEach(function(t){return(a=t).isIntersecting||0<a.intersectionRatio?q(t.target,t,i,o):(e=t.target,n=t,a=i,t=o,void(u(e)||(_(e,a.class_exited),$(e,n,a,t),f(a.callback_exit,e,n,t))));var e,n,a})}function J(e,n){var t;et&&!H(e)&&(n._observer=new IntersectionObserver(function(t){B(t,e,n)},{root:(t=e).container===document?null:t.container,rootMargin:t.thresholds||t.threshold+"px"}))}function K(t){return Array.prototype.slice.call(t)}function Q(t){return t.container.querySelectorAll(t.elements_selector)}function W(t){return c(t)===_t}function X(t,e){return e=t||Q(e),K(e).filter(u)}function Y(e,t){var n;(n=Q(e),K(n).filter(W)).forEach(function(t){v(t,e.class_error),r(t)}),t.update()}function t(t,e){var n,a,t=i(t);this._settings=t,this.loadingCount=0,J(t,this),n=t,a=this,Z&&window.addEventListener("online",function(){Y(n,a)}),this.update(e)}var Z="undefined"!=typeof window,tt=Z&&!("onscroll"in window)||"undefined"!=typeof navigator&&/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),et=Z&&"IntersectionObserver"in window,nt=Z&&"classList"in document.createElement("p"),at=Z&&1<window.devicePixelRatio,it={elements_selector:".lazy",container:tt||Z?document:null,threshold:300,thresholds:null,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",data_bg:"bg",data_bg_hidpi:"bg-hidpi",data_bg_multi:"bg-multi",data_bg_multi_hidpi:"bg-multi-hidpi",data_poster:"poster",class_applied:"applied",class_loading:"litespeed-loading",class_loaded:"litespeed-loaded",class_error:"error",class_entered:"entered",class_exited:"exited",unobserve_completed:!0,unobserve_entered:!1,cancel_on_exit:!0,callback_enter:null,callback_exit:null,callback_applied:null,callback_loading:null,callback_loaded:null,callback_error:null,callback_finish:null,callback_cancel:null,use_native:!1},ot="src",rt="srcset",ct="sizes",lt="poster",st="llOriginalAttrs",ut="loading",dt="loaded",ft="applied",_t="error",vt="native",gt="data-",bt="ll-status",pt=[ut,dt,ft,_t],ht=[ot],mt=[ot,lt],Et=[ot,rt,ct],It={IMG:function(t,e){m(t,function(t){A(t,Et),x(t,e)}),A(t,Et),x(t,e)},IFRAME:function(t,e){A(t,ht),w(t,ot,l(t,e.data_src))},VIDEO:function(t,e){a(t,function(t){A(t,ht),w(t,ot,l(t,e.data_src))}),A(t,mt),w(t,lt,l(t,e.data_poster)),w(t,ot,l(t,e.data_src)),t.load()}},yt=["IMG","IFRAME","VIDEO"],At={IMG:P,IFRAME:function(t){k(t,ht)},VIDEO:function(t){a(t,function(t){k(t,ht)}),k(t,mt),t.load()}},kt=["IMG","IFRAME","VIDEO"];return t.prototype={update:function(t){var e,n,a,i=this._settings,o=X(t,i);{if(h(this,o.length),!tt&&et)return H(i)?(e=i,n=this,o.forEach(function(t){-1!==kt.indexOf(t.tagName)&&F(t,e,n)}),void h(n,0)):(t=this._observer,i=o,t.disconnect(),a=t,void i.forEach(function(t){a.observe(t)}));this.loadAll(o)}},destroy:function(){this._observer&&this._observer.disconnect(),Q(this._settings).forEach(function(t){y(t)}),delete this._observer,delete this._settings,delete this.loadingCount,delete this.toLoadCount},loadAll:function(t){var e=this,n=this._settings;X(t,n).forEach(function(t){b(t,e),V(t,n,e)})},restoreAll:function(){var e=this._settings;Q(e).forEach(function(t){U(t,e)})}},t.load=function(t,e){e=i(e);V(t,e)},t.resetStatus=function(t){r(t)},Z&&function(t,e){if(e)if(e.length)for(var n,a=0;n=e[a];a+=1)o(t,n);else o(t,e)}(t,window.lazyLoadOptions),t});!function(e,t){"use strict";function a(){t.body.classList.add("litespeed_lazyloaded")}function n(){console.log("[LiteSpeed] Start Lazy Load Images"),d=new LazyLoad({elements_selector:"[data-lazyloaded]",callback_finish:a}),o=function(){d.update()},e.MutationObserver&&new MutationObserver(o).observe(t.documentElement,{childList:!0,subtree:!0,attributes:!0})}var d,o;e.addEventListener?e.addEventListener("load",n,!1):e.attachEvent("onload",n)}(window,document);</script></body>
				
			

CSS Code:

				
					body {
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: #f0f0f0;
    font-family: Arial, sans-serif;
    margin: 0;
}

.game {
    text-align: center;
    background-color: #fff;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 20px rgba(0,0,0,0.1);
    max-width: 400px;
    width: 100%;
}

.header {
    margin-bottom: 20px;
}

.info-container {
    display: flex;
    justify-content: space-between;
    margin-bottom: 20px;
    padding: 0 10px;
}

.info-item {
    font-size: 20px;
}

.mode-selection {
    margin-bottom: 20px;
}

.mode-selection label {
    font-size: 16px;
}

.mode-selection select {
    font-size: 16px;
    padding: 5px;
    margin-left: 10px;
}

.mole-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    max-width: 300px;
    margin: 20px auto;
}

.hole {
    width: 100px;
    height: 100px;
    background-color: #8b5e3c;
    position: relative;
    border-radius: 10px;
    overflow: hidden; /* Ensure mole is hidden when off-screen */
}

.mole {
    width: 80px;
    height: 80px;
    background-color: #d4af37;
    border-radius: 50%;
    position: absolute;
    bottom: -100px; /* Start off-screen */
    left: 50%;
    transform: translateX(-50%);
    cursor: pointer;
    transition: bottom 0.3s, opacity 0.3s;
    opacity: 0; /* Start invisible */
}

.mole.up {
    bottom: 10px;
    opacity: 1; /* Fully visible when up */
}

button {
    padding: 10px 20px;
    font-size: 16px;
    cursor: pointer;
    background-color: #28a745;
    color: #fff;
    border: none;
    border-radius: 5px;
    margin-top: 20px;
}

button:hover {
    background-color: #218838;
}

button:focus {
    outline: none;
}

button:active {
    background-color: #1e7e34;
}

				
			

JavaScript Code:

				
					const holes = document.querySelectorAll(".hole");
const moles = document.querySelectorAll(".mole");
const scoreBoard = document.getElementById("score");
const highScoreBoard = document.getElementById("highScore");
const timeLeftBoard = document.getElementById("timeLeft");
const modeBoard = document.getElementById("mode");
const modeSelect = document.getElementById("modeSelect");
const startButton = document.getElementById("startButton");
let lastHole;
let timeUp = false;
let score = 0;
let highScore = 0;
let timeLeft = 30;
let mode = "easy";
let peepTime = 1000;
let gameTimer;
let moleTimer;

function setPeepTime(mode) {
  switch (mode) {
    case "easy":
      return 1000;
    case "medium":
      return 800;
    case "hard":
      return 600;
    default:
      return 1000;
  }
}

function randomTime(min, max) {
  return Math.round(Math.random() * (max - min) + min);
}

function randomHole(holes) {
  const idx = Math.floor(Math.random() * holes.length);
  const hole = holes[idx];
  if (hole === lastHole) {
    return randomHole(holes);
  }
  lastHole = hole;
  return hole;
}

function peep() {
  const time = randomTime(peepTime - 300, peepTime);
  const hole = randomHole(holes);
  const mole = hole.querySelector(".mole");
  mole.classList.add("up");
  moleTimer = setTimeout(() => {
    mole.classList.remove("up");
    if (!timeUp) peep();
  }, time);
}

function startGame() {
  clearInterval(gameTimer);
  clearTimeout(moleTimer);
  scoreBoard.textContent = 0;
  timeLeftBoard.textContent = 30;
  modeBoard.textContent = mode.charAt(0).toUpperCase() + mode.slice(1);
  score = 0;
  timeLeft = 30;
  peepTime = setPeepTime(mode);
  timeUp = false;
  peep();
  gameTimer = setInterval(() => {
    timeLeft--;
    timeLeftBoard.textContent = timeLeft;
    if (timeLeft <= 0) {
      clearInterval(gameTimer);
      timeUp = true;
      updateHighScore();
      alert("Game Over! Your score is " + score);
    }
  }, 1000);
}

function bonk(e) {
  if (!e.isTrusted) return; // Cheater!
  score++;
  this.classList.remove("up");
  scoreBoard.textContent = score;
}

function updateHighScore() {
  if (score > highScore) {
    highScore = score;
    highScoreBoard.textContent = highScore;
  }
}

moles.forEach((mole) => mole.addEventListener("click", bonk));
startButton.addEventListener("click", startGame);
modeSelect.addEventListener("change", (e) => {
  mode = e.target.value;
});

				
			

Related Articles

FAQ's

1. Can you make a 3D game in JavaScript?

One of the most widely used 3D game engines among developers is js. It offers built-in functions to speed up the implementation of common 3D functionality, just like any other 3D library.

2. How to code a game with JavaScript?

→ How to Write JavaScript Code for a Game.

  1. Choose a code editor.
  2. Create a game canvas in step two.
  3. Code Your Player.
  4. Give Your Player Code Functionality.
  5. Code Jump Logic for Your Player.
  6. Construct the Attack Block.
3. What is the whack-a-mole game called?

An arcade game known as Whack-A-Mole, It was developed in 1975 in Japan under the name Mogura Taiji by the entertainment company TOGO.

Join Our Mailing List

Sign up for the latest news and updates.