1. 개요
두더지 잡기 게임이다. 여섯개의 hole에서 무작위로 두더지가 등장했다가 사라지며, 이 속도 또한 랜덤이다. 두더지를 클릭하면 점수가 1씩 올라간다.
2. HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Whack A Mole!</title>
<link href='https://fonts.googleapis.com/css?family=Amatic+SC:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="style.css">
</head>
<body>
<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>
<div class="hole hole2">
<div class="mole"></div>
</div>
<div class="hole hole3">
<div class="mole"></div>
</div>
<div class="hole hole4">
<div class="mole"></div>
</div>
<div class="hole hole5">
<div class="mole"></div>
</div>
<div class="hole hole6">
<div class="mole"></div>
</div>
</div>
</body>
</html>
3. CSS
html {
box-sizing: border-box;
font-size: 10px;
background: #ffc600;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
padding: 0;
margin: 0;
font-family: 'Amatic SC', cursive;
}
h1 {
text-align: center;
font-size: 10rem;
line-height: 1;
margin-bottom: 0;
}
.score {
background: rgba(255,255,255,0.2);
padding: 0 3rem;
line-height: 1;
border-radius: 1rem;
}
.game {
width: 600px;
height: 400px;
display: flex;
flex-wrap: wrap;
margin: 0 auto;
}
.hole {
flex: 1 0 33.33%;
overflow: hidden;
position: relative;
}
.hole:after {
display: block;
background: url(dirt.svg) bottom center no-repeat;
background-size: contain;
content: '';
width: 100%;
height:70px;
position: absolute;
z-index: 2;
bottom: -30px;
}
.mole {
background: url('mole.svg') bottom center no-repeat;
background-size: 60%;
position: absolute;
top: 100%;
width: 100%;
height: 100%;
transition:all 0.4s;
}
.hole.up .mole {
top: 0;
}
4. Javascript
function randomTime(min, max) {
return Math.round(Math.random() * (max - min) + min);
}
먼저 randomTime 함수를 설정한다. 최솟값과 최댓값을 받아, 둘의 차이에 랜덤 수를 곱하고 최솟값을 더하여 반올림한 수를 반환한다. Math.random()은 0 이상 1 미만의 수를 무작위로 반환하는데, 위와 같이 Math.random() * (max - min) + min 형태로 사용하면 max와 min 사이의 무작위 숫자를 반환하게 된다. 반환되는 무작위 수를 x라고 하면, 0 <= x < 1이므로, 0 <= x * (max - min) < max - min이 되고, min < x * (max - min) + min < max이 되기 때문이다. 따라서 주어진 두 수 max와 min의 차이가 클수록 큰 수가 반환되고, 짧을수록 짧은 수가 반환될 확률이 커질 것이다. 이는 게임의 난이도를 조절할 때 사용될 수 있다.
const holes = document.querySelectorAll('.hole');
let lastHole;
function randomHole(holes) {
const idx = Math.floor(Math.random() * holes.length);
const hole = holes[idx];
if (hole === lastHole) {
return randomHole(holes);
}
lastHole = hole;
return hole;
}
다음으로는 randomHole을 만들기 위해 hole 클래스를 가진 태그를 모두 선택하고 holes 변수에 할당한다. idx에는 0에서 1 사이의 무작위 숫자에 holes의 길이를 곱하여 내린 값을 할당하여 무작위 인덱스 값이 반환되도록 하는데, 이 범위는 0에서 최대 holes의 길이 값이다. 이를 반올림한다는 것은 즉, holes의 길이 내, 구멍의 개수 내에서 무작위로 숫자를 반환한다는 의미가 된다. 이렇게 무작위로 반환될 idx 값에 맞는 holes의 요소를 선택한 것이 hole에 할당된다.
또, 같은 수가 연속으로 반환되지 않게 만들어 주는 장치가 필요하므로, lastHole을 선언한다. 조건이 없을 때는 무작위 숫자 idx로 선택한 hole을 lastHole에 할당하고 hole을 반환하지만, 만약 hole이 lastHole과 같은 경우, 즉, 연속해서 같은 hole이 선택되는 경우에는 자기 자신을 반환하여 randomHole을 재실행한다.
let timeUp = false;
function peep() {
const time = randomTime(200, 1000);
const hole = randomHole(holes);
hole.classList.add('up');
setTimeout(() => {
hole.classList.remove('up');
if(!timeUp) peep();
}, time);
}
다음은 위에서 만든 두 개의 랜덤 함수인 randomTime과 randomHole을 실행시키는 함수 peep을 만든다. 먼저 randomTime에 최솟값 200, 최댓값 1000을 전달하여 실행한 return값, 즉, 0.2초에서 1초 사이의 무작위 숫자를 time 변수에 할당하고, 무작위로 선택된 hole을 hole에 할당한다. 이 hole에 up 클래스를 추가하면, 하위 요소인 mole의 top 값이 0이 되어 두더지가 위로 올라오게 될 것이다. 여기에 setTimeout을 설정하여 다시 up 클래스를 제거하되, 시간은 무작위로 설정하기 위해 time을 입력한다. 또한, timeUp 플래그를 만들어 !timeUp이 참인 경우에 peep 함수, 즉 자기자신을 재실행하도록 한다. 이로써 timeUp이 True가 아닌 한(false인 한), 무작위 구멍에서 무작위 시간동안 두더지가 올라왔다가 내려가는 것이 지속적으로 반복될 것이다.
const scoreBoard = document.querySelector('.score');
let score = 0;
function startGame() {
scoreBoard.textContent = 0;
timeUp = false;
score = 0;
peep();
setTimeout(() => timeUp = true, 10000);
}
게임을 시작하고 끝내기 위해 startGame 함수를 만든다. 먼저 scoreBoard를 선택하여 변수에 할당하고, 처음 score를 0으로 만든다. startGame 함수는 scoreBoard의 text 내용과 score를 0으로 초기화하고, 플래그인 timeUp을 false로 만든 후 peep 함수를 실행시켜 두더지들이 튀어나오도록 한다. 이후 setTImeout을 걸어 10초 뒤 timeUp을 true로 만들어 peep의 실행을 중지시킨다.
const moles = document.querySelectorAll('.mole');
function bonk(e) {
if(!e.isTrusted) return;
score++;
this.classList.remove('up');
scoreBoard.textContent = score;
}
moles.forEach(mole => mole.addEventListener('click', bonk));
마지막으로 두더지를 클릭하면 점수가 올라가는 기능이다. 모든 moles를 선택하고, 각각의 mole에 클릭에 반응하여 bonk 함수를 실행하는 이벤트 리스너를 건다. Event.isTrusted는 이벤트가 사용자 행위에 의해 발생되었다면 true, 이벤트가 스크립트로 인해 생성되거나 dispatchEvent를 통해 보내졌다면 false를 반환한다. 즉, !e.isTrusted라면 아무것도 반환하지 않는다는 조건에 의해, 오직 사용자의 클릭에 의해서만 점수를 올리도록 만든다. 클릭될 때마다 score에 1씩 점수를 추가하고, 클릭된 대상인 this에서 up 클래스를 제거하며, 스코어 보드에 스코어를 표시한다.
[Javascript] 29. Countdown Timer (0) | 2021.05.13 |
---|---|
[Javascript] 28. Video Speed Controller (0) | 2021.05.12 |
[Javascript] 27. Click and Drag (0) | 2021.05.11 |
[Javascript] 26. Stripe Follow Along Nav (0) | 2021.05.09 |
[Javascript] 25. Event Capture, Propagation, Bubbling and Once (0) | 2021.05.08 |
댓글 영역