今天是最後一天!就以 JS 30 最後一篇打地鼠作結。
範例連結
首先是 HTML 的架構。
<!-- 計分板 -->
<h1>Whack-a-mole! <span class="score">0</span></h1>
<!-- 開始鈕 -->
<button onClick="startGame()">Start!</button>
<div class="game">
<!-- 洞裡面躲地鼠-->
<div class="hole hole1">
<div class="mole"></div>
</div>
<!-- 中間省略 2 ~ 5 -->
<div class="hole hole6">
<div class="mole"></div>
</div>
</div>
要怎麼讓打地鼠運行呢?
首先要讓地鼠在隨機的時間內從隨機的洞洞冒出來。地鼠界又把這個規則稱作「地鼠亂竄原理」。
接著,要讓地鼠被打擊到時,獲得分數!
最後,讓遊戲在固定時間內結束,並且有按鈕可以重啟遊戲。
只要滿足這三個條件,就可以得到一台網頁打地鼠機。
來看看要怎麼隨機時間隨機洞洞,首先是隨機時間:
// 隨機時間
function randTime(min, max) {
return Math.round(Math.random() * (max - min) + min);
}
隨機時間比較單純,傳入最大值跟最小值,計算出最大值跟最小值之間的整數隨機值並回傳即可。
再來是隨機洞洞:
const holes = document.querySelectorAll('.hole');
let lastHole;
// 隨機地洞
function randHole(holes) {
const idx = Math.floor(Math.random() * holes.length);
const hole = holes[idx];
if(hole === lastHole) {
console.log('Repeat hole.');
randHole(holes);
}
lastHole = hole;
return hole;
}
隨機洞洞我們另外給個限制,不希望地鼠連續好幾次出現在同個洞洞。為此必須記錄上一個洞洞 lastHole
。
holes
得到的是所有洞洞元素組成的清單,用 length
屬性取得洞洞總量,接著用 Math.random()
配合 Math.floor()
製造出隨機的洞洞編號,就可以指定隨機洞洞了。
設置條件,如果和最後一次出現的洞重複了,就重跑一次函式,直到跑出新的洞為止。
記得在函式末端將這次的洞記錄為最後一次出現的洞,下次跑函式時才能用來判斷重複。然後回傳洞洞結果。
接著要來利用隨機時間跟隨機洞洞讓地鼠亂竄了。請看以下程式碼:
// 遊戲時間到會顯示 true
let timeUp = false;
function peep() {
const time = randTime(200, 800);
const hole = randHole(holes);
hole.classList.add('up');
setTimeout(() => {
hole.classList.remove('up');
if(!timeUp) peep();
}, time)
}
peep()
函式每次啟動時,會先用 randHole(holes)
選個隨機洞,然後冒出來!在0.2 ~ 0.8秒的隨機時間 randTime(200, 800)
後鑽回去。如果遊戲時間還沒到,就會呼叫新的 peep()
讓新的地鼠冒出來!
棒,來看看怎麼打擊到這些地鼠:
const moles = document.querySelectorAll('.mole');
const scoreBoard = document.querySelector('.score');
function bonk(e) {
if(!e.isTrusted) return;
score++;
this.classList.remove('up');
scoreBoard.textContent = score;
}
moles.forEach(mole => mole.addEventListener('click', bonk))
讓這些該死的地鼠被點擊到都會讓你的分數增加,並且被打到的地鼠就讓它縮回地洞。
但是如果我寫程式碼狂點地鼠不就好了?這時候可以用滑鼠點擊事件的 isTrusted
屬性來阻止假點擊, isTrusted
可以分辨這個點擊是否為玩家操控,或是自動觸發的。
最後是讓遊戲開始:
function startGame() {
scoreBoard.textContent = 0;
timeUp = false;
score = 0;
peep();
setTimeout(() => timeUp = true, 10000);
}
遊戲開始前一般都會有初始化的動作,例如分數歸零,遊戲時間結束的判斷重置等等,初始化後就設置計時器並讓第一個地鼠冒出來即可。
以上就是 JS 30 最終章!終於完賽了,透過這三十天的練習成長了不少,希望這些成長紀錄也有幫助到擁有同樣困擾的人們!如果有什麼好想法歡迎討論!再會了!謝謝大家!