[JS30] Day30: Whack a Mole
這一天的實作是要做一個打地鼠的遊戲,地鼠會隨機從六個洞出現,不定時下降,滑鼠點擊到地鼠時,會加分。

HTML
主要是有個分數版、六個坑洞,值得注意的是.mole為地鼠,每個坑洞都有各自的地鼠。
<h1>Whack-a-mole! <span class="score">0</span></h1>
<div class="content" style="display: flex; justify-content: center">
<button onClick="startGame()">Start!</button>
</div>
<div class="game">
<div class="hole hole1">
<div class="mole"></div>
</div>
<div class="hole hole2">
<div class="mole"></div>
</div>
<div class="hole hole3">
<div class="mole"></div>
</div>
<div class="hole hole4">
<div class="mole"></div>
</div>
<div class="hole hole5">
<div class="mole"></div>
</div>
<div class="hole hole6">
<div class="mole"></div>
</div>
</div>
CSS
.hole相對定位,.mole定位在他的下方(top: 100%),且因為overflow:hidden而隱藏。
.hole:after為泥土,z-index: 2使得有地鼠從泥土出現的感覺。
.hole {
flex: 1 0 33.33%;
overflow: hidden;
position: relative;
}
.hole:after {
display: block;
background: url(dirt.svg) bottom center no-repeat;
background-size: contain;
content: "";
width: 100%;
height: 70px;
position: absolute;
z-index: 2;
bottom: -30px;
}
.mole {
background: url("mole.svg") bottom center no-repeat;
background-size: 60%;
position: absolute;
top: 100%;
width: 100%;
height: 100%;
transition: all 0.4s;
}
.hole.up .mole {
top: 0;
/* 上方推移為0,地鼠出現 */
}
JS
選取元素和定義變數
const holes = document.querySelectorAll(".hole");
const scoreBoard = document.querySelector(".score");
const moles = document.querySelectorAll(".mole");
let lastHole; // 為了不要在重複的地洞出現,需紀錄上次地洞在哪
let timeUp = false; // 控制遊戲結束
let score = 0;
隨機的時間出現,此種給予最小、最大值函式做法很常見
function randomTime(min, max) {
return Math.round(Math.random() * (max - min) + min);
}
randomHole傳回隨機的地洞
function randomHole(holes) {
const idx = Math.floor(Math.random() * holes.length);
const hole = holes[idx];
if (hole === lastHole) {
console.log("Ah nah thats the same one bud");
return randomHole(holes); // 若是與上次相同,則再次執行
}
lastHole = hole;
return hole;
}
peep為地鼠出現函式,透過前面的隨機時間,會出現隨機地洞的地鼠(加上up的 class)
function peep() {
const time = randomTime(200, 1000);
const hole = randomHole(holes);
hole.classList.add("up");
setTimeout(() => {
hole.classList.remove("up");
if (!timeUp) peep();
}, time);
}
startGame開始遊戲,會重製分數、倒數時間
function startGame() {
scoreBoard.textContent = 0;
score = 0;
timeUp = false;
peep();
setTimeout(() => {
timeUp = true;
}, 10000); // 預設為10秒(10000毫秒)
}
bonk 打地鼠,會確定是滑鼠點擊(e.isTrusted)在會使地鼠下降與加分。
function bonk(e) {
if (!e.isTrusted) return; // cheater!!
score++;
this.classList.remove("up");
scoreBoard.textContent = score;
}
moles.forEach((mole) => mole.addEventListener("click", bonk));