I´m working in a whack-a-mole game in vanilla JS (following this tutorial https://www.youtube.com/watch?v=rJU3tHLgb_c&t=1s) and I would like to display a random image every time the mole appears on the screen instead of the same mole image. Right now what I get is the same random image repeated in each square. This is not what I want and I don´t understand why this is happening. I would appreciate any help!
const squares = document.querySelectorAll('.square'); const mole = document.querySelector('.mole'); const timeLeft = document.querySelector('#time-left'); const score = document.querySelector('#score'); const bgColorArray = ['https://res.cloudinary.com/dkwiijqr0/image/upload/v1630402761/Whack-a-mole/sample-mole_in4rlk.png', 'https://res.cloudinary.com/dkwiijqr0/image/upload/v1630347923/Whack-a-mole/mole-img_antxud.png'], selectBG = bgColorArray[Math.floor(Math.random() * bgColorArray.length)]; let result = 0; let hitPosition; let currentTime = 60; let timerId = null; function randomSquare() { squares.forEach((square) => { square.classList.remove('mole'); }); let randomSquare = squares[Math.floor(Math.random() * 9)]; randomSquare.classList.add('mole'); hitPosition = randomSquare.id; document.querySelector(".mole").style.backgroundImage = 'url(' + selectBG + ')'; } squares.forEach((square) => { square.addEventListener('mousedown', () => { if (square.id == hitPosition) { result++; score.textContent = result; hitPosition = null; } }); }); function moveMole() { timerId = setInterval(randomSquare, 500); } moveMole(); function countDown() { currentTime--; timeLeft.textContent = currentTime; if (currentTime == 0) { clearInterval(countDownTimerId); clearInterval(timerId); alert('GAME OVER! Your final score is ' + result); } } let countDownTimerId = setInterval(countDown, 1000);
.grid { width: 606px; height: 606px; display: flex; flex-wrap: wrap; } .square { height: 200px; width: 200px; border: solid black 1px; } .mole { background-size: cover; }
<h2>Your score:</h2> <h2 id="score">0</h2> <h2>Time Left:</h2> <h2 id="time-left">60</h2> <div class="grid"> <div class="square" id="1"></div> <div class="square" id="2"></div> <div class="square" id="3"></div> <div class="square" id="4"></div> <div class="square" id="5"></div> <div class="square" id="6"></div> <div class="square" id="7"></div> <div class="square" id="8"></div> <div class="square" id="9"></div> </div>
Advertisement
Answer
You just have to move the definition of selectBG
in the function randomSquare()
. Otherwise you will always use the same selectBG
which you defined as constant at the beginning (where the random function runs only once).
If you only want one background image to be visible you have to reset the backgrounds for all squares at that point where you remove the class .mole
from all squares.
squares.forEach((square) => { square.classList.remove('mole'); square.style.backgroundImage = ''; });
Working example:
const squares = document.querySelectorAll('.square'); const mole = document.querySelector('.mole'); const timeLeft = document.querySelector('#time-left'); const score = document.querySelector('#score'); const bgColorArray = ['https://res.cloudinary.com/dkwiijqr0/image/upload/v1630402761/Whack-a-mole/sample-mole_in4rlk.png', 'https://res.cloudinary.com/dkwiijqr0/image/upload/v1630347923/Whack-a-mole/mole-img_antxud.png']; let result = 0; let hitPosition; let currentTime = 60; let timerId = null; function randomSquare() { squares.forEach((square) => { square.classList.remove('mole'); square.style.backgroundImage = ''; }); let randomSquare = squares[Math.floor(Math.random() * 9)]; randomSquare.classList.add('mole'); let selectBG = bgColorArray[Math.floor(Math.random() * bgColorArray.length)]; hitPosition = randomSquare.id; document.querySelector(".mole").style.backgroundImage = 'url(' + selectBG + ')'; } squares.forEach((square) => { square.addEventListener('mousedown', () => { if (square.id == hitPosition) { result++; score.textContent = result; hitPosition = null; } }); }); function moveMole() { timerId = setInterval(randomSquare, 500); } moveMole(); function countDown() { currentTime--; timeLeft.textContent = currentTime; if (currentTime == 0) { clearInterval(countDownTimerId); clearInterval(timerId); alert('GAME OVER! Your final score is ' + result); } } let countDownTimerId = setInterval(countDown, 1000);
.grid { width: 606px; height: 606px; display: flex; flex-wrap: wrap; } .square { height: 200px; width: 200px; border: solid black 1px; } .mole { background-size: cover; }
<h2>Your score:</h2> <h2 id="score">0</h2> <h2>Time Left:</h2> <h2 id="time-left">60</h2> <div class="grid"> <div class="square" id="1"></div> <div class="square" id="2"></div> <div class="square" id="3"></div> <div class="square" id="4"></div> <div class="square" id="5"></div> <div class="square" id="6"></div> <div class="square" id="7"></div> <div class="square" id="8"></div> <div class="square" id="9"></div> </div>