Wesbos - 두더지 잡기


완성본 예시

음… 실용성은 없을 것 같지만 그래도 그동안 배웠던 JS 지식들을 잘 활용할 수 있는 챕터였다.
클릭해서 올라오는 두더지를 잡고, 잡은 수 만큼 스코어를 올리면 된다.


로직

  1. const & addEventListener
  2. “랜덤으로 반복되지 않게” 두더지가 올라오도록 하기 ( + 들어가는 것 까지)
  3. 두더지가 클릭된 횟수를 기억하기
  4. 해당 횟수를 스코어보드에 기록하기

const

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

randomHole 함수를 만들어 보자

💡 임의의 두더지 구멍(hole)이 반환될 수 있도록 Math.random() 을 활용해보자

1
2
3
4
5
function randomHole() {
const index = Math.floor(Math.random() * holes.length);
const hole = holes[index];
console.log(hole);
}

다 좋은데, 아래와 같이 동일한 hole이 출력된다.
이 게임에선 난이도 조절을 위해 같은 hole에서 두더지가 나오지 않도록 할 것이기 때문에 아래와 같은 중복 반환 현상이 일어나선 안된다…!

똑같은 두더지가 나오면 안됨

1
2
3
4
5
6
7
8
9
10
11
12
let lastHole;

function randomHole() {
const index = Math.floor(Math.random() * holes.length);
const hole = holes[index];
if (hole == lastHole) {
console.log('이미 나온 놈..!!');
return randomHole();
}
lastHole = hole; // 여기서 hole은 lasthole로 지정된다.
console.log(hole);
}

두 값 사이의 난수 생성하기?

💡 예를 들어, 1과 5 사이에 있는 숫자들 중에 난수를 반환하고자 한다면, 아래와 같은 함수 및 공식을 활용하면 된다.

1
2
3
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}

두더지가 튀어나오도록 해보자

1
2
3
4
function popUp() {
const hole = randomHole(holes);
hole.classList.add('up');
}

두더지

하지만! 들어가는 속도가 너무 일정하면 게임이 너무 쉽다… 그래서 들어가는 속도도 랜덤으로 해보고자 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function randomTime(min, max) {
return Math.round(Math.random() * (max - min) + min);
}

function popUp() {
// 0.2초 ~ 1초 사이의 랜덤한 숫자(초)를 반환한다.
const time = randomTime(200, 1000);
const hole = randomHole(holes);
hole.classList.add('up');
// 0.2초 ~ 1초 사이에서 임의의 속도로 두더지는 다시 들어간다.
setTimeout(() => {
hole.classList.remove('up');
}, time);
}

점수 계산

1
2
3
4
5
6
7
8
9
function scored(e) {
if (e.isTrusted == false) {
alert("Don't Cheating!!");
return;
}
score++;
this.parentNode.classList.remove('up');
scoreBoard.textContent = score;
}

isTrusted

💡 클릭 이벤트가 진짜 사용자에 의한 “물리적 클릭“에 의해서 이루어졌는지 확인할 수 있음


게임 시작버튼 활성화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function popUp() {
const time = randomTime(200, 1000);
const hole = randomHole(holes);
hole.classList.add('up');
setTimeout(() => {
hole.classList.remove('up');
if (!finished) popUp(); // 10초가 지나기 전까진 계속 false이므로 popUp돼야 함!
}, time);
}

function start() {
popUp();
finished = false;
setTimeout(() => (finished = true), 10000); // 게임은 10초동안 진행된다.
}

최종 완성 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const holes = document.querySelectorAll('.hole');
const scoreBoard = document.querySelector('.score');
const moles = document.querySelectorAll('.mole');
let lastHole;
let finished = false;
let score = 0;

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

function randomHole(holes) {
const index = Math.floor(Math.random() * holes.length);
const hole = holes[index];
if (hole == lastHole) {
console.log('이미 나온 놈!!');
return randomHole(holes);
}
lastHole = hole;
return hole;
}

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

function scored(e) {
if (e.isTrusted == false) {
alert("Don't Cheating!!");
return;
}
score++;
this.parentNode.classList.remove('up');
scoreBoard.textContent = score;
}

function start() {
scoreBoard.textContent = 0;
popUp();
finished = false;
setTimeout(() => (finished = true), 10000);
}

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

Author

Hoonjoo

Posted on

2022-01-05

Updated on

2022-02-07

Licensed under

Comments