돈이 만드는 세상
반응속도 체크 게임 - zerocho ES2021 강의 본문
시간과 관련된 메서드를 제공하는 Date 객체를 사용하는 웹게임입니다.
여기서 포인트는 <화면>과 <자바스크립트 코드>를 일치시키는 것이다. 예를 들어, 빨강 화면 = 자바스크립트 변수 이런식으로 구성해서 게임을 만드는 것이다.
태그에 특정한 역할이 부여되었다는 의미로 class를 붙혀준다. id를 붙혀주어도 되지만, 이미 태그 선택자로 쓰기 위해 id로 쓰였기 때문에 class를 구현하였다.
자바스크립트 내에서 html의 class를 가져오기 위해서는 <className>을 이용하면 된다.
여러개의 클래스를 가져오려면 <classList>를 이용하면 된다.
태그.classList.contains('클래스')
시간 재는 거에 있어 중요한 부분은 setTimeout()을 통해 비동기로 타이머가 시작되는데 시간을 재는 코드가 타이머가 시작하기 전에 작동할 수 있다는 주의점이 있다. 타이머 코드가 비동기라는 것을 고려해 문제를 해결해야 한다.
new Date(2021, 2, 31, 18, 30, 5);
// Wed Mar 31 2021 18:30:05 GMT+0900 (대한민국 표준시)
배열로써 저장되지 않고, "객체"로써 저장된다. 그리고 month의 경우 0부터 시작한다는게 특이한 점이다. 서양 사람들은 월을 단어로 하기 때문에 0부터 시작하는 것으로 판단된다.
배열의 합을 구하는 방법으로 좋은 메서드가 있다. 바로 <reduce>이다.
[1, 2, 3, 4].reduce((a, b) => a + b, 0);
// a: 0 b: 1
// a: 1 b: 2
// a: 3 b: 3
// a: 6 b: 4
// 10
reduce는 배열에서 꼭 알아두어야하는 메서드이다. 배열.reduce((a, b) => a + b, 초기값) a는 누적값, b는 현재값이다. 초기값이 처음 누적값이 된다. 반복문처럼 배열의 끝까지 가게 되는 것이다. 덧셈말고도 응용해서 곱셈을 한다든지 나눗셈을 한다든지 모두 가능하다.
초기값을 안 넣으면 첫 번째 값이 초기값으로 자동 설정된다.
['철수', '영희', '현영', '한솔'].reduce((a, c, i) => {a[i] = c; return a}, {})
// {0: '철수', 1: '영희', 2: '현영', 3: '한솔'}
// 0: "철수"
// 1: "영희"
// 2: "현영"
// 3: "한솔"
reduce를 이용해 배열을 객체 리터럴로도 바꿀 수 있다. a라는 객체를 리턴한다. 하지만, 객체를 배열로 바꿀 때 reduce를 사용하지는 않는다.
자바스크립트 코드
const $screen = document.querySelector('#screen');
const $result = document.querySelector('#result');
const $average = document.querySelector('#average');
const $button = document.querySelector('#check');
const $high = document.querySelector('#high');
let startTime;
let endTime;
let timeoutId;
const records = [];
$screen.addEventListener('click', (event) => {
if(event.target.classList.contains('waiting')) { // 파랑
$screen.classList.remove('waiting');
$screen.classList.add('ready');
$screen.textContent = `초록색이 되면 클릭하세요.`;
timeoutId = setTimeout(function() {
$screen.classList.remove('ready');
$screen.classList.add('now');
$screen.textContent = `클릭하세요!!!!!!!`;
// 시간 재기
startTime = new Date();
}, Math.floor(Math.random() * 1000) + 2000); // 2000 ~ 3000 사이 수(2s~3s)
} else if(event.target.classList.contains('ready')) { // 빨강
clearTimeout(timeoutId);
$screen.classList.remove('ready');
$screen.classList.add('waiting');
startTime = null;
endTime = null;
$screen.textContent = `너무 성급했습니다. 다시 하십시오.`;
} else if(event.target.classList.contains('now')) { // 초록
// 끝 시간 재기
endTime = new Date();
// 시간 차이 저장하기
$result.appendChild(document.createTextNode(`${endTime - startTime}ms `));
records.push(endTime - startTime);
records.sort();
$high.textContent = null;
if(records.length < 5) {
for(let i = 0; i < records.length; i++) {
$high.append(document.createElement('br'), document.createTextNode(`${i+1}등 ${records[i]}ms`));
}
} else {
for(let i = 0; i < 5; i++) {
$high.append(document.createTextNode(`${i+1}등 ${records[i]}ms`, document.createElement('br')));
}
}
/* 강의에 있는 최고 5개 고르는 방법 -> 이 방법으로 하기 위해서는 내가 짠 코드의 수정이 필요. 이유는 appendChild를 통해 반응속도를 추가했기 때문에 코드에 문제가 발생.
const topFive = records.sort((p, c) => p - c).slice(0, 5); // 정렬한 후 5개만 빼고 잘라내서 배열로써 topFive에 할당
topFive.forEach((top, index) => {
$result.append( // result에 append함으로써 하나하나씩 추가해나감.
document.createElement('br'),
`${index + 1}위: ${top}ms`,
);
});
*/
$screen.classList.remove('now');
$screen.classList.add('waiting');
startTime = null;
endTime = null;
$screen.textContent = `클릭해서 시작하세요.`;
}
});
$button.addEventListener('click', () => {
if(records.length === 0) {
$average.textContent = `현재 시도한 횟수가 0번입니다.`;
} else {
let sum = records.reduce((a, b) => a + b);
$average.textContent = `총${records.length}번 시도 하셨습니다. ${sum / records.length}ms가 평균 반응속도입니다.`;
}
});
전체 코드
<html>
<head>
<meta charset="utf-8" />
<title>반응속도</title>
<style>
#screen {
width: 300px;
height: 200px;
text-align: center;
user-select: none;
}
#screen.waiting {
background-color: aqua;
}
#screen.ready {
background-color: red;
color: white;
}
#screen.now {
background-color: greenyellow;
}
</style>
</head>
<body>
<div id="screen" class="waiting">클릭해서 시작하세요</div>
<button id="check">현재 평균 반응속도 계산</button>
<div id="result"></div>
<div id="average"></div>
<div id="high"></div>
<script>
const $screen = document.querySelector('#screen');
const $result = document.querySelector('#result');
const $average = document.querySelector('#average');
const $button = document.querySelector('#check');
const $high = document.querySelector('#high');
let startTime;
let endTime;
let timeoutId;
const records = [];
$screen.addEventListener('click', (event) => {
if(event.target.classList.contains('waiting')) { // 파랑
$screen.classList.remove('waiting');
$screen.classList.add('ready');
$screen.textContent = `초록색이 되면 클릭하세요.`;
timeoutId = setTimeout(function() {
$screen.classList.remove('ready');
$screen.classList.add('now');
$screen.textContent = `클릭하세요!!!!!!!`;
// 시간 재기
startTime = new Date();
}, Math.floor(Math.random() * 1000) + 2000); // 2000 ~ 3000 사이 수(2s~3s)
} else if(event.target.classList.contains('ready')) { // 빨강
clearTimeout(timeoutId);
$screen.classList.remove('ready');
$screen.classList.add('waiting');
startTime = null;
endTime = null;
$screen.textContent = `너무 성급했습니다. 다시 하십시오.`;
} else if(event.target.classList.contains('now')) { // 초록
// 끝 시간 재기
endTime = new Date();
// 시간 차이 저장하기
$result.appendChild(document.createTextNode(`${endTime - startTime}ms `));
records.push(endTime - startTime);
records.sort();
$high.textContent = null;
if(records.length < 5) {
for(let i = 0; i < records.length; i++) {
$high.append(document.createElement('br'), document.createTextNode(`${i+1}등 ${records[i]}ms`));
}
} else {
for(let i = 0; i < 5; i++) {
$high.append(document.createTextNode(`${i+1}등 ${records[i]}ms`, document.createElement('br')));
}
}
/* 강의에 있는 최고 5개 고르는 방법 -> 이 방법으로 하기 위해서는 내가 짠 코드의 수정이 필요. 이유는 appendChild를 통해 반응속도를 추가했기 때문에 코드에 문제가 발생.
const topFive = records.sort((p, c) => p - c).slice(0, 5); // 정렬한 후 5개만 빼고 잘라내서 배열로써 topFive에 할당
topFive.forEach((top, index) => {
$result.append( // result에 append함으로써 하나하나씩 추가해나감.
document.createElement('br'),
`${index + 1}위: ${top}ms`,
);
});
*/
$screen.classList.remove('now');
$screen.classList.add('waiting');
startTime = null;
endTime = null;
$screen.textContent = `클릭해서 시작하세요.`;
}
});
$button.addEventListener('click', () => {
if(records.length === 0) {
$average.textContent = `현재 시도한 횟수가 0번입니다.`;
} else {
let sum = records.reduce((a, b) => a + b);
$average.textContent = `총${records.length}번 시도 하셨습니다. ${sum / records.length}ms가 평균 반응속도입니다.`;
}
});
</script>
</body>
</html>
'프로그래밍 > JavaScript' 카테고리의 다른 글
틱택토 게임 - zerocho 2021ES 강의 (0) | 2021.11.09 |
---|---|
객체 다루기_가위바위보 게임- zerocho ES2021 강의 (0) | 2021.11.03 |
숫자야구 코드 및 설명 - zerocho ES2021 강의 (0) | 2021.11.02 |
로또 추첨기 코드 및 로또 뽑기 코드 - zerocho ES 2021 강의 (0) | 2021.11.02 |