iT邦幫忙

2022 iThome 鐵人賽

DAY 29
0

30 - Whack A Mole

tags: JavaScript30

專案簡介

第三十天要實作的專案是一個打地鼠的小遊戲

課程影片:JS30 30
導讀影片:Alex

初始文件

Github 檔案位置:30 - Whack A Mole

網站的樣子

可以先看看最後的成果

正式製作

首先,先選取好今天會操作到的 DOM 元素和變數

const holes = document.querySelectorAll('.hole');
const scoreBoard = document.querySelector('.score');
const moles = document.querySelectorAll('.mole');

let lastHole; // 最後一個地鼠洞
let timeUp = false; // 遊戲進行與否
let score = 0; // 分數

這裡先來寫關於亂數的函式,我們需要一個函式名為 randomTime 決定地鼠的出現時長,以及 randomHole 決定是哪隻地鼠出現

randomHole 的實現主要是依造 holes 的陣列長度做 random,再以此索引去求出值,並紀錄最後出現的地鼠索引值,在隨機出跟上一次相同位置時重新 random

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) {
    console.log('Ah nah thats the same one bud');
    return randomHole(holes);
  }
  lastHole = hole;
  return hole;
}


再來就是要設定讓隨機到的地鼠出來的函式了,首先以寫好的亂數函式產生出現時長的 time 和地鼠位置的 hole,接著再加上寫好的 CSS class,並在 time 毫秒後移除

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,主要是將遊戲設定初始化,譬如 timeUpscorescoreBoard 等,並執行 peep 函式,最後以定時器來設定結束時間

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

因為在 HTML 已經綁好函式的關係,案下旁邊白色的 Start 按鈕後就會開始了


最後最後,終於要來加上打地鼠的事件啦~

forEach 函式幫每隻地鼠加上 click 事件,這裡的 bonk 函式邏輯非常簡單,只需要在觸發事件時移除 CSS class 並加一分更新分數即可

值得一提的是 e.isTrusted 會在以腳本觸發事件時回傳 false,可以讓使用者乖乖玩遊戲 XD

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

moles.forEach(mole => mole.addEventListener('click', bonk));

最後程式碼

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);
}

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;
}

function peep() {
  const time = randomTime(1000, 2000);
  const hole = randomHole(holes);
  hole.classList.add('up');
  setTimeout(() => {
    hole.classList.remove('up');
    if (!timeUp) peep();
  }, time);
}

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

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

moles.forEach(mole => mole.addEventListener('click', bonk));

完成結果

最後的成品

結語

以上是第三十天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<

Make a Whack A Mole Game with Vanilla JS - #JavaScript30 30/30
[ Alex 宅幹嘛 ] ?‍? 深入淺出 Javascript30 快速導覽 | Day 30:Whack A Mole
MDN Web Docs


上一篇
JS30 -> 29 - Countdown Timer
下一篇
# JS30 -> 總心得
系列文
剛接觸前端一個月的小白 - JavaScript30 挑戰筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言