<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UP & DOWN</title>
<!-- css -->
<!-- reset -->
<!-- custom -->
<!-- <link rel="stylesheet" href="main.css"> -->
<!-- js -->
<!-- <script type="text/javascript" src="./1.app.js" defer></script> -->
</head>
<body>
<div class="wrapper">
<section class="main">
<h1 class="main-title">신나는 UP&DOWN 게임</h1>
<div class="number-wrapper">
<h2>
<em id="begin">1</em>부터 <em id="end">100</em>사이의 숫자를 클릭하세요.
</h2>
<div id="numbers">
</div>
</div>
</section>
<aside class="result">
<div id="up">UP!!</div>
<div id="down">DOWN!!</div>
</aside>
<div id="finish">Congratulation!!!</div>
</div>
</body>
</html>
/*reset*/
a {
color: inherit;
text-decoration: none;
}
/* common layout */
.wrapper {
font-size: 18px;
background: #8c8c8c;
height: 100vh;
position: relative;
}
/* section.main */
section.main {
width: 40%;
background: #fff;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 10px;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.7);
overflow: hidden;
}
section.main .main-title {
font-size: 30px;
font-weight: 700;
background: #a3f8ff;
text-align: center;
padding: 30px 20px;
border-bottom: 1px solid #d3d3d3;
}
section.main .number-wrapper {
padding: 50px 20px;
}
section.main .number-wrapper h2 {
font-size: 22px;
text-align: center;
text-decoration: underline;
}
section.main .number-wrapper h2 em {
font-size: 1.2em;
font-weight: 700;
color: #f00;
}
#numbers {
width: 70%;
height: 400px;
border: 1px solid #000;
margin: 30px auto 0;
padding: 30px 0 30px 50px;
overflow: auto;
display: flex;
flex-wrap: wrap;
}
#numbers .icon {
width: 90px;
height: 90px;
border-radius: 50%;
font-size: 32px;
font-weight: 700;
color: #fff;
background: #000;
display: flex;
justify-content: center;
align-items: center;
margin-right: 5%;
margin-bottom: 10px;
cursor: pointer;
}
#numbers .icon:hover {
transform: scale(1.1);
opacity: 0.7;
}
#numbers .icon:nth-child(4n + 1) {
background: orange;
}
#numbers .icon:nth-child(4n + 2) {
background: skyblue;
}
#numbers .icon:nth-child(4n + 3) {
background: yellowgreen;
}
#numbers .icon:nth-child(4n) {
background: orangered;
}
/* aside.result */
.result {
position: absolute;
right: 20%;
top: 50%;
transform: translateY(-50%);
}
.result div {
width: 150px;
height: 150px;
border-radius: 50%;
font-size: 30px;
font-weight: 700;
color: #fff;
margin-bottom: 30px;
display: flex;
justify-content: center;
align-items: center;
background: #000;
}
#up {
background: #f00;
cursor: pointer;
}
#down {
background: #00f;
cursor: pointer;
}
.result div.selected {
animation: jump 0.3s infinite linear alternate;
}
@keyframes jump {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
100% {
transform: translateY(-20px);
}
}
/* #finish */
#finish {
width: 60%;
height: 200px;
background: tomato;
font-size: 80px;
font-weight: 700;
border: 2px solid #000;
border-radius: 20px;
text-align: center;
line-height: 200px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
z-index: -100;
opacity: 0;
}
#finish.show {
animation: drop 1s linear forwards;
}
@keyframes drop {
0% {
opacity: 0;
top: -50%;
}
50% {
opacity: 0.5;
top: 0;
}
100% {
opacity: 1;
z-index: 100;
top: 50%;
}
}
/* 정답아이콘에 id=move가 붙으면 아이콘이 이동하는 애니메이션 */
.icon#move {
position: absolute;
left: 50%;
top: 10%;
z-index: 50;
border: 4px dashed #000;
animation: move 1s linear forwards;
}
@keyframes move {
0% {
top: 0;
transform: scale(1) rotate(0) translateX(0);
}
100% {
top: 10%;
transform: scale(2) rotate(720deg) translateX(-50%);
}
}
//=============== 전역변수, 함수 정의부분 =============//
// 게임진행에 필요한 데이터
// (실제정답, 선택한숫자, 최소값, 최대값)
const gameData = {
secret: Math.floor(Math.random() * 100) + 1,
answer: null,
min: 1,
max: 100
};
// 숫자 아이콘 생성 함수
function makeIcons() {
const $numbers = document.getElementById('numbers');
//가상의 태그
const $virtual = document.createDocumentFragment();
for (let i = 1; i <= 100; i++) {
const $newDiv = document.createElement('div');
$newDiv.textContent = i;
$newDiv.classList.add('icon');
$virtual.appendChild($newDiv);
}
$numbers.appendChild($virtual);
}
// UP, DOWN일 경우 해야할 일 정의
// parameter 1: isUp - UP인경우 true, DOWN인 경우 false
// parameter 2: target - 클릭된 요소 노드
function processUpDownCase(isUp, target) {
const CLASS_NAME = 'selected';
const [$up, $down] = [...document.querySelector('.result').children]
if (isUp) {
$down.classList.remove(CLASS_NAME);
$up.classList.add(CLASS_NAME);
gameData.min = gameData.answer + 1;
document.getElementById('begin').textContent = gameData.min;
} else {
$up.classList.remove(CLASS_NAME);
$down.classList.add(CLASS_NAME);
gameData.max = gameData.answer - 1;
document.getElementById('end').textContent = gameData.max;
}
// 아이콘 제거 함수 호출
clearIcons(isUp, target);
}
// 클릭한 아이콘을 기준으로 범위밖의 아이콘을 제거하는 함수
function clearIcons(isUp, target) {
const $numbers = document.getElementById('numbers');
let $delTarget = target;
while($delTarget) {
let $nextTarget =
isUp ?
$delTarget.previousElementSibling
: $delTarget.nextElementSibling;
$numbers.removeChild($delTarget);
$delTarget = $nextTarget;
}
}
// 정답을 맞출 경우 해야할 일
function processCorrectCase(target) {
const $finish = document.getElementById('finish');
$finish.classList.add('show');
// 정답 div.icon에 id=move를 추가.
target.setAttribute('id','move');
}
// 사용자가 선택한 숫자를 실제정답과 비교해서 결과를 처리하는 함수
function compareAnswer(target) {
if (gameData.answer === gameData.secret) {
//정답인 경우
processCorrectCase(target);
} else if (gameData.answer < gameData.secret) {
//UP인 경우
processUpDownCase(true, target);
} else {
//DOWN인 경우
processUpDownCase(false, target);
}
}
//=============== 메인 코드 실행부분 ===============//
(function() {
// 100개의 아이콘 생성하여 배치
makeIcons();
// 아이콘 클릭 이벤트 부여
const $numbers = document.getElementById('numbers');
$numbers.addEventListener('click', e => {
//만약에 아이콘을 클릭하지 않았다면 나가!
if (!e.target.matches('#numbers > .icon')) return;
// 사용자가 선택한 숫자가 무엇인가???
// console.log(e.target.textContent);
gameData.answer = +e.target.textContent;
// console.log(gameData);
// 정답 검증하는 함수 호출
compareAnswer(e.target);
});
})();
/*
# 시나리오
- 사용자는 100개의 아이콘 중 한 개를 클릭한다.
- 시스템은 정답데이터(1~100사이의 랜덤정수)와
클릭한 아이콘의 숫자데이터를 비교한다.
- 시스템은 비교결과를 판단하여 UP인경우 DOWN인 경우 그리고 정답인 경우에 따른 효과를 렌더링한다.
- 사용자는 지속적으로 정답을 맞출 때 까지 위의 행위를 반복한다.
===============================
# 세부 시나리오
1. 100개의 아이콘에는 클릭 이벤트가 부여되어야 한다
2-1. UP인 경우
=> up아이콘의 애니메이션을 발동시킨다.
=> 해당 범위에 벗어난 아이콘을 제거한다.
=> h2태그의 최소값을 수정한다.
2-2. down인 경우
=> down아이콘의 애니메이션을 발동시킨다.
=> 해당 범위에 벗어난 아이콘을 제거한다.
=> h2태그의 최대값을 수정한다.
2-3. 정답인 경우
=> finish박스의 애니메이션을 발동시킨다.
===============================
# 필요한데이터
1-100사의 랜덤정수(고정값),
사용자가 클릭한 아이콘의 숫자,
최소값을 저장할 변수, 최대값을 저장할 변수
*/
'javascript' 카테고리의 다른 글
javascript_(이벤트위임_응용)_22.05.09(day11) (0) | 2022.05.09 |
---|---|
javascript_(이벤트위임1)_22.05.09(day11) (0) | 2022.05.09 |
javascript_(preventDefault())_22.05.09(day11) (0) | 2022.05.09 |
javascript_(이벤트전파)_22.05.09(day11) (0) | 2022.05.09 |
javascript_(이벤트객체)_22.05.09(day11) (0) | 2022.05.09 |