JS30 讀書會 Day 30 - Whack A Mole Game!

摘要

打地鼠!

最後一天要實作的是打地鼠的遊戲,打地鼠的內容如下:

有六個洞會隨機出現地鼠,對著地鼠點擊即可得一分,遊戲時間10秒鐘。

想像需要甚麼功能

可以把要實現的效果拆分,可以比較了解每一個小功能要幹嘛

  1. 地鼠隨機出現的時間
  2. 地鼠從六個洞隨機出現的位置
  3. 結合 1. 2. 做出地鼠隨機出現
  4. 點到地鼠時,分數++

隨機時間

地鼠出現的隨機時間

我們希望有個 function 可以接收兩個時間作為參數,並且回傳兩個參數之間的一個隨機數。

  • Math.random() 隨機回傳 0~1 之間 (0 <= 回傳值 < 1),的一個隨機小數。
function randomTime(min, max) {
	return Math.round(Math.random() * (max - min)) + min
}

或是

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

補充:

如果跳太快可以先看這個對於 Math.random() 的初階用法。

// 求一個 0~指定數之間的隨機數
function randomNum(num) {
	return Math.floor(Math.random() * num ) 
}

randomNum(10) // 回傳 0~9 的隨機數

[筆記][JavaScript]用Math.random()取得亂數的技巧

[筆記][JavaScript]用Math.random()取得某區間內的隨機亂數

隨機的地鼠洞洞

隨機從六個洞其中一個洞出現

我們希望有個 function 可以接受綁定全部 hole 的 DOM 元素作為參數,並隨機回傳其中一的 holes 的元素。

並且不希望他會連續兩次從相同的地洞冒出,所以在外面新增一個變數 lastHole 用來記住上次是從哪個洞冒出,並做判斷式。

lastHole = hole

function randomHole(holes) {
  const idx = Math.floor(Math.random() * holes.length)
  const hole = holes[idx]
  // console.log(hole)
  // 不希望他會連續兩次從相同的洞洞迸出來 建立一個新變數存取最後的 hole
  if (hole === lastHole) {
    console.log('重複了!')
    return randomHole(holes)
  }
  lastHole = hole
  return hole
}

地鼠隨機冒出

地鼠冒出機制:地鼠隨機從六個洞冒出,並停留隨機的時間

合併上面的兩個 function 即可做出

為了停止,在外面宣告一個新變數用來停止地鼠冒出,這邊先加判斷式,停止的功能由下一個函式實作。

let timeUp = false

function peep() {
  const peepTime = randomTime(200, 1000)
  const peepHole = randomHole(holes)
  // console.log(peepTime, peepHole)
  peepHole.classList.add('up')
  // 這樣地鼠冒出的機制就完成了,接下來要讓它消失
  setTimeout(() => {
    // 加上這行,讓他會縮回去
    peepHole.classList.remove('up')
    //再加上 peep(),隨機出現的地鼠就完成囉!
    if(!timeUp) peep()
  }, peepTime)
}

遊戲開始

遊戲開始:在一定時間內。地鼠隨機從六個洞冒出,並停留隨機的時間

將上面的函式加上停止的條件,並且設定遊戲開始的初始值,即可做出

  • setTimeout 設定一定時間後 timeUp 就會變成 true,這個用來判斷遊戲何時停止
  • 初始值:記分板的分數、分數、設定停止的參數為 false
let timeUp = false

function startGame() {
  scoreBoard.textContent = 0
  timeUp = false
  score = 0 
  peep()
  setTimeout(() => timeUp = true, 10000)
}

這樣子就有得到一個遊戲開始的函式,只要執行他就會在時間內隨機的從地洞中跑出地鼠,接下來剩下點擊地鼠的計分事件囉~

記得將開始的監聽掛上。

document.querySelector('.start').addEventListener('click', startGame)

點擊地鼠計分事件

點擊到地鼠時分數++,記分板的分數同步

// 將地鼠掛上監聽
moles.forEach(mole => mole.addEventListener('click', bonk))
  • Event.isTrusted 若事件物件是由使用者操作而產生,則 isTrusted 值為 true。簡單的防作弊機制。

MDN Event.isTrusted

function bonk(e) {
  // console.log(e)
  if(!e.isTrusted) return // 作弊仔
  score++
  // 點到之後馬上把 up 拿掉
  this.parentNode.classList.remove('up')
  scoreBoard.textContent = score
}

最後只要點擊 start ,就可以開始玩啦~

不知道甚麼時候會死的連結

謝謝大家,JS30 我要成為 JavaScript 大師 讀書會 平安落幕。

感謝 benben 的發起(?,還有大家的邀請

相信大家都有像當初的目標一樣,向 JS 大師邁進了一步!

第一個讀書會結束了,希望這個社群的第二個、第三個讀書會能繼續持續下去

我們下個讀書會見。

Select a repo