Javascript

Javascript30 - day30 Whack A Mole Game

joy_lee 2021. 5. 11. 13:55

목표

두더지 잡기 게임 구현하기

-시작 버튼을 누르면 게임을 시작하고, 10초 후에 게임을 종료한다.

-두더지가 무작위로 올라오고, 올라갔다 내려오는 시간도 무작위로 설정한다.

-두더지를 클릭하면 title옆에 숫자가 바뀌고, 총 몇 마리를 잡았는지 알려준다.

 

어떻게 해야 할지 감이 안잡혀서 영상을 보며 같이 코드를 작성했다.

영상의 코드

만들어야 할 함수

-무작위 시간을 출력하는 함수

-두더지가 나올 구멍을 정하는 함수

(같은 곳을 연속으로 두번 선택하지 않도록 한다. 설정하지 않으면 클릭해도 새로운 두더지가 나와있어서 들어가지 않게된다.)

-두더지가 나오게 하는 함수

-게임을 시작하는 함수

-클릭했을 때 두더지가 다시 들어가고, 점수를 올려주는 함수 - addEventListener로 연결

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const holes = document.querySelectorAll('.hole');
const scoreBoard = document.querySelector('.score');
const moles = document.querySelectorAll('.mole');
let lastHole;
 
function randomHole(holes) {
    // random index between 0 and holes.length
    const idx = Math.floor(Math.random() * holes.length);
    const hole = holes[idx];
    if(hole === lastHole) {
        console.log('thats the same one')
        return randomHole(holes);
    }
 
    lastHole = hole;
    return hole;
}
cs

randomHole 함수를 만든다. holes를 받는다.

Math.random()(0-1사이 수)와 holes.length를 곱해서 0~holes의 개수 사이의 수를 무작위로 만든다.

(min이 0이므로 위의 randomTime을 만들 때 처럼 할 필요가 없다)

hole[idx]로 random한 hole을 선택한다.

lastHole 변수에 선택한 hole을 저장해 다음에 hole을 고를 땐 이전의 hole과 겹치지 않게 선택하도록 한다.

return hole;을 해야 재귀함수를 사용할 수 있다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let timeUp = false;
 
function randomTime(min, max) {
    return Math.round(Math.random() * (max - min) + min);
}
 
function peep() {
    const time = randomTime(2001000);
    const hole = randomHole(holes);
    hole.classList.add('up'); // top:100%; -> top:0
    setTimeout(() => {
        hole.classList.remove('up');
        if(!timeUp) peep();
    }, time);
}
 
cs

randomTime 함수를 만든다. 입력한 min, max 사이의 숫자를 무작위로 출력한다.

 

peep 함수를 만든다.(mole가 hole에서 나오게함)

randomTime()으로 무작위 숫자를 만들어 time에 입력한다.

randomHole()으로 무작위로 선택된 hole을 hole에 입력한다.

선택된 hole에 'up' class를 추가해 위치를 이동시킨다(top:100% -> top: 0;)

setTimeout으로 time이 지나면 'up' class를 제거하고,

timeUp 변수가 false이면 새로운 두더지가 나오도록 peep()을 실행한다.

 

1
2
3
4
5
6
7
8
9
10
let score = 0;
 
function startGame() {
    scoreBoard.textContent = 0;
    timeUp = false;
    score = 0;
    peep();
    // stop the game after 10 seconds
    setTimeout(() => timeUp = true10000);
}
cs

점수를 위한 score 변수를 전역변수로 만든다.
게임을 시작할 때 scoreBoard의 점수를 0점으로 표시하고, score도 0으로 초기화해준다.
게임이 시작하자마자 peep();을 실행한다.
setTimeout을 통해 10000ms = 10s가 지나면 timeUp=true로 설정해줘서 peep()가 멈추도록 한다.
startGame()은 <button onClick="startGame()">Start!</button>으로 HTML에서 바로 함수와 연결시켜준다.

 

1
2
3
4
5
6
7
8
function bonk(e) {
    if (!e.isTrusted) return// cheater!
    score++;
    this.classList.remove('up');
    scoreBoard.textContent = score;
}
 
moles.forEach(mole => mole.addEventListener('click', bonk));
cs

두더지를 클릭했을 때 실행할 bonk 함수를 만든다.

e.isTrusted는 event에 속하는 읽기전용 속성이다.

사용자의 행위에 의해 생성된 이벤트라면 true를(trusted event),

이벤트가 스크립트를 통해 생성되었거나 dispatchEvent를 통해 보내졌다면 false인 논리값이다.

두더지를 클릭한 것이 사용자가 마우스로 클릭한건지 확인해서 false이면 바로 return을 통해 함수를 마친다.

e.isTrusted=true;이면 score를 1점 올리고, 두더지를 다시 내려가게 하고, scoreBoard에 score를 갱신한다.

 

참고) developer.mozilla.org/ko/docs/Web/API/Event/isTrusted

 

Event.isTrusted - Web API | MDN

Event 인터페이스의 읽기 전용 속성인 isTrusted는, 이벤트가 사용자 행위에 의하여 발생되었으면 true이고 이벤트가 스크립트로 인해 생성 또는 수정되었거나 dispatchEvent를 통해 보내졌으면 false

developer.mozilla.org

새롭게 알게된 점

어떻게 기능을 구현해야 할 지 모를 땐 세세한 것 하나하나 기능을 생각해서 함수로 구현할 생각을 해보자.

기능이 구현되지 않을땐 오타를 확인하자...! (scoreBoard.textContext로 써서 점수 갱신이 안돼서 한참 코드를 들여다봤다.)

두더지가 나왔다가 들어갔다가 하는 것을 구연하는게 어려울 거라고 생각했는데 생각보다 쉬운 방법이었다.

(위치가 위로 올라왔다가, 시간이 지나면 아래로 내려감 / 아래로 내려가면서 다른 두더지 위로 올라옴)

어떤 문제를 해결해야 할 때 쉽게 할 수 있는 방법을 생각해보자.

세세한 부분을 잘 신경써야 완성도가 높아지는 것 같다.

(연속해서 같은 곳에서 두더지 나오지 않도록 randomHole에서 lastHole확인, bonk에서 클릭 이벤트가 신뢰할만한지 확인)