[TIL] 210930

Lee Syong·2021년 9월 30일
0

TIL

목록 보기
43/204
post-thumbnail

📝 오늘 한 것

  1. 미니 게임 구현 중

  2. getBoundingClientRect() / offsetTOP VS clientTOP / setInterval() / clearInterval() / Audio 객체 / 배경만 흐리게 / 페이지에 특정 요소가 있는지 확인하는 방법


📚 배운 것

당근만 클릭해야 하는 게임

게임 이름 뭐라고 해야 하지
어제 풀이에서 이어서


📌 구현 내용 쪼개기

  1. 초기 화면에 보여야 할 것들

1) 게임 시작 버튼
2) 타이머 (0:0이라고 적혀 있음)
3) 클릭 가능 횟수 (0이라고 적혀 있음)

  1. 게임 시작 버튼을 클릭하면

1) 필드 안에 당근 10개과 벌레 7마리가 랜덤한 위치에 배치되어야 한다.
2) 타이머가 작동해야 한다. (10초부터 시작)
3) 클릭 가능 횟수가 10으로 바뀌어야 한다.
4) bg.mp3 배경음이 재생되어야 한다.
5) 게임 시작 버튼 안의 아이콘이 중지 아이콘으로 바뀌어야 한다.

  1. 당근을 클릭하면

1) carrot_pull.mp3 효과음이 들려야 한다.
2) 클릭 가능 횟수가 1씩 줄어들어야 한다.
3) 클릭된 당근이 화면에서 사라져야 한다.

  1. 벌레를 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) bug_pull.mp3 효과음이 들려야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) YOU LOST 문구와 함께 재시작 버튼이 떠야 한다.

  1. 제한 시간 내에 모든 당근을 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) game_win.mp3 음악이 재생되어야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) YOU WON 문구와 함께 재시작 버튼이 떠야 한다.

  1. 제한 시간 내에 모든 당근을 클릭하지 못하면

1) bg.mp3 배경음이 멈춰야 한다.
2) 게임 시작 버튼이 없어져야 한다.
3) YOU LOST 문구와 함께 재시작 버튼이 떠야 한다.

  1. 게임 중지 버튼을 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) alert.wav 효과음이 들려야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) REPLAY 문구와 함께 재시작 버튼이 떠야 한다.

  1. 재시작 버튼을 클릭하면

1) 이전 게임의 당근과 벌레가 없어져야 한다.
2) replay ❓ 창이 없어져야 한다.
3) 다시 2.가 일어나야 한다. - (1), (3)만
4) 타이머가 '다시 처음부터' 작동해야 한다.
5) bg.mp3 배경음이 '다시 처음부터' 재생되어야 한다.
6) 게임 시작 버튼이 다시 보여야 한다.


2. 게임 시작 버튼을 클릭하면

  1. 게임 시작 버튼을 클릭하면

1) 필드 안에 당근 10개와 벌레 7마리가 랜덤한 위치에 배치되어야 한다.
2) 타이머가 작동해야 한다. (10초부터 시작)
3) 클릭 가능 횟수가 10으로 바뀌어야 한다.
4) bg.mp3 배경음이 재생되어야 한다.
5) 게임 시작 버튼 안의 아이콘이 중지 아이콘으로 바뀌어야 한다.

💡 이미지 여러 개를 랜덤한 위치에 배치하기

클릭시 이미지를 임의의 위치에 표시하는 방법 답변 #2 참고

(1) getBoundingClientRect() 사용

// 2. 게임 시작 버튼을 클릭하면
startBtn.addEventListener('click', function startGame () {
  // 1) field 안에 당근 10개와 벌레 7마리가 랜덤한 위치에 배치되어야 한다.
  const rect = field.getBoundingClientRect();

  for (let i = 0; i < 10; i++) {
    const carrot = document.createElement('img');
    carrot.setAttribute('src', 'img/carrot.png');
    carrot.setAttribute('alt', 'carrot');

    carrot.style.left = rect.left + (rect.width - 120) * Math.random() + 'px';
    carrot.style.top = rect.top + (rect.height - 120) * Math.random() + 'px';

    carrot.style.width = '120px';
    field.appendChild(carrot);
  }

  for (let i = 0; i < 7; i++) {
    const bug = document.createElement('img');
    bug.setAttribute('src', 'img/bug.png');
    bug.setAttribute('alt', 'bug');

    bug.style.left = rect.left + (rect.width - 80) * Math.random() + 'px';
    bug.style.top = rect.top + (rect.height - 80) * Math.random() + 'px';

    bug.style.width = '80px';
    field.appendChild(bug);
  }
});

(2) getBoundingClientRect() 사용 x

HTML Element 객체에서 제공하는 크기 및 위치 프로퍼티와 메소드 참고

아래는 offsetTop과 clientTop 개념이 헷갈려서 정리하는 김에 작성해본 것
실제 코드는 (1)로 작성함

// 2. 게임 시작 버튼을 클릭하면
startBtn.addEventListener('click', function startGame () {
  // 1) field 안에 당근 10개와 벌레 7마리가 랜덤한 위치에 배치되어야 한다.
  for (let i = 0; i < 10; i++) {
    const carrot = document.createElement('img');
    carrot.setAttribute('src', 'img/carrot.png');
    carrot.setAttribute('alt', 'carrot');

    carrot.style.left = field.offsetLeft + (field.clientWidth - 120) * Math.random() + 'px';
    carrot.style.top = field.offsetTop + (field.clientHeight - 120) * Math.random() + 'px';

    carrot.style.width = '120px';
    field.appendChild(carrot);
  }

  for (let i = 0; i < 7; i++) {
    const bug = document.createElement('img');
    bug.setAttribute('src', 'img/bug.png');
    bug.setAttribute('alt', 'bug');

    bug.style.left = field.offsetLeft + (field.clientWidth - 80) * Math.random() + 'px';
    bug.style.top = field.offsetTop + (field.clientHeight - 80) * Math.random() + 'px';

    bug.style.width = '80px';
    field.appendChild(bug);
  }
});

💡 setInterval() 이용해서 타이머 만들기

자바스크립트 타이머 만들기 참고

  • 처음에 10부터 시작하도록 적었다가 버튼이 눌리자마자 10이 뜰 수 있도록 innerHTML로 추가한 후 10을 9로 바꿈
let time = 9;

// 2. 게임 시작 버튼을 클릭하면
startBtn.addEventListener('click', function startGame () {
  // 2) 타이머가 작동해야 한다.
  timer.innerHTML = `0:10`;
  const decreNum = setInterval(function () {
    const second = time % 60;
    timer.innerHTML = `0:${second}`;
    time--;

    if (time < 0) {
      clearInterval(decreNum);
    }
  }, 1000);
});

📌 2번째 요구 사항 - 코드 모음

// html에서 받아온 요소들
const startBtn = document.querySelector('.setting-startBtn');
const timer = document.querySelector('.setting-timer');
const clickLimit = document.querySelector('.setting-limit');
const field = document.querySelector('.field');

let time = 9; // 타이머 관련

// 2. 게임 시작 버튼을 클릭하면
startBtn.addEventListener('click', function startTimer () {
  // 1) field 안에 당근 10개와 벌레 7마리가 랜덤한 위치에 배치되어야 한다.
  const rect = field.getBoundingClientRect();

  for (let i = 0; i < 10; i++) {
    const carrot = document.createElement('img');
    carrot.setAttribute('src', 'img/carrot.png');
    carrot.setAttribute('alt', 'carrot');

    carrot.style.left = rect.left + (rect.width - 120) * Math.random() + 'px';
    carrot.style.top = rect.top + (rect.height - 120) * Math.random() + 'px';

    carrot.style.width = '120px';
    field.appendChild(carrot);
  }

  for (let i = 0; i < 7; i++) {
    const bug = document.createElement('img');
    bug.setAttribute('src', 'img/bug.png');
    bug.setAttribute('alt', 'bug');

    bug.style.left = rect.left + (rect.width - 80) * Math.random() + 'px';
    bug.style.top = rect.top + (rect.height - 80) * Math.random() + 'px';

    bug.style.width = '80px';
    field.appendChild(bug);
  }

  // 2) 타이머가 작동해야 한다.
  timer.innerHTML = `0:10`;
  const decreNum = setInterval(function () {
    const second = time % 60;
    timer.innerHTML = `0:${second}`;
    time--;

    if (time < 0) {
      clearInterval(decreNum);
    }
  }, 1000);

  // 3) 클릭 가능 횟수가 10으로 바뀌어야 한다.
  clickLimit.innerHTML = 10;

  // 4) bg.mp3 배경음이 재생되어야 한다.
  const bg_mp3 = new Audio('sound/bg.mp3');
  bg_mp3.play();

  // 5) 시작 버튼이 중지 버튼으로 바뀌어야 한다.
  startBtn.innerHTML = '<i class="fas fa-stop"></i>';
});

3. 당근을 클릭하면

  1. 당근을 클릭하면

1) carrot_pull.mp3 효과음이 들려야 한다.
2) 클릭 가능 횟수가 1씩 줄어들어야 한다.
3) 클릭된 당근이 화면에서 사라져야 한다.

💡 이벤트 위임 응용

📌 3번째 요구 사항 - 코드 모음

// field 안을 클릭했을 때
field.addEventListener('click', function (event) {
  // 3. 클릭된 게 당근이면
  if (event.target.alt === 'carrot') {

    // 1) carrot_pull.mp3 효과음이 들려야 한다.
    const carrot_mp3 = new Audio('sound/carrot_pull.mp3');
    carrot_mp3.play();

    // 2) 클릭 가능 횟수가 1씩 줄어들어야 한다.
    clickLimit.innerHTML = clickLimit.innerHTML - 1;

    // 3) 클릭된 당근이 화면에서 사라져야 한다.
    event.target.remove();
  }
});

4. 벌레를 클릭하면

  1. 벌레를 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) bug_pull.mp3 효과음이 들려야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) YOU LOST 문구와 함께 재시작 버튼이 떠야 한다.

💡 배경만 흐리게 하는 법 (내부 요소에는 영향 x)

  • opacity 사용 x
  • 대신, background-color: rgba(0, 0, 0, 0.5) 사용

💡 CSS 수정

  • div.result를 당근과 벌레 위에 올리기 위해 div.field에 position: positive를 적용하니까, 기존에 브라우저 창을 기준으로 position: absolute 가 적용되어 있던 당근과 벌레가 밑으로 내려가버림

  • 이를 해결하기 위해 div.field에 position: relative 를 추가하고, 당근과 벌레를 랜덤한 위치에 띄우기 위해 적어줬던 rect.left와 rect.top 부분을 삭제함

💡 타이머 생성 코드를 함수로 만들어 따로 빼냄

  • 게임 시작 버튼을 클릭했을 때뿐 아니라 벌레를 클릭했을 때도 타이머를 컨트롤하기 위해, 타이머 생성 코드를 함수로 만들어, 게임 시작 버튼의 이벤트 리스너 코드 블럭 안에서 global scope로 옮김

📌 4번째 요구 사항 - 코드 모음

// 🔎 타이머
let time = 9;
let decreNum;

function startWorkingTimer () {
  decreNum = setInterval(function () {
    const second = time % 60;
    timer.innerHTML = `0:${second}`;
    time--;

    if (time < 0) {
      clearInterval(decreNum);
    }
  }, 1000);
}

// 🔎 ~ 문구 & 재시작 버튼
function displayResult (text) {
  const gameResult = document.createElement('div');
  gameResult.classList.add('result');
  gameResult.innerHTML = `
    <button class="replayBtn" type="button"><i class="fas fa-redo"></i></button>
    <p>${text}</p>
  `;
  field.appendChild(gameResult);
}

// 🔎 field 안을 클릭했을 때
field.addEventListener('click', function (event) {
  // 4. 클릭된 게 벌레라면
  if (event.target.alt === 'bug') {

    // 1) bg.mp3 배경음이 멈춰야 한다.
    bg_mp3.pause();

    // 2) bug_pull.mp3 효과음이 들려야 한다.
    const bug_mp3 = new Audio('sound/bug_pull.mp3');
    bug_mp3.play();

    // 3) 타이머가 멈춰야 한다.
    clearInterval(decreNum);

    // 4) 게임 시작 버튼이 없어져야 한다.
    startBtn.style.visibility = 'hidden';

    // 5) YOU LOST 문구와 함께 재시작 버튼이 떠야 한다.
    displayResult('YOU LOST');
  }
});

5. 제한 시간 내에 모든 당근을 클릭하면

  1. 제한 시간 내에 모든 당근을 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) game_win.mp3 음악이 재생되어야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) 게임 YOU WON 문구와 함께 재시작 버튼이 떠야 한다.

💡 아래 코드를 div.field의 이벤트 리스너 코드 블럭 안에 추가함

💡 페이지 내에 특정 요소가 없으면 표기하는 방법

  • 확인할 요소가 하나일 경우
if (document.querySelector('img[alt="carrot"]') === null)
  • 확인할 요소가 배열의 형태일 경우
if (document.querySelectorAll('img[alt="carrot"]').length === 0)

💡 '4. 벌레를 클릭하면'과 겹치는 코드가 많지만, 일단은 전부 쭉 적어줬다

📌 5번째 요구 사항 - 코드 모음

// 5. 제한 시간 내에 모든 당근을 클릭하면
if (time > 0) {
  if (document.querySelectorAll('img[alt="carrot"]').length === 0) {

    // 1) bg.mp3 배경음이 멈춰야 한다.
    bg_mp3.pause();

    // 2) game_win.mp3 음악이 재생되어야 한다.
    win_mp3.play();

    // 3) 타이머가 멈춰야 한다.
    clearInterval(decreNum);

    // 4) 게임 시작 버튼이 없어져야 한다.
    startBtn.style.visibility = 'hidden';

    // 5) 게임 YOU WON 문구와 함께 재시작 버튼이 떠야 한다.
    displayResult('YOU WON');
  }
}

6. 제한 시간 내에 모든 당근을 클릭하지 못하면

  1. 제한 시간 내에 모든 당근을 클릭하지 못하면

1) bg.mp3 배경음이 멈춰야 한다.
2) 게임 시작 버튼이 없어져야 한다.
3) YOU LOST 문구와 함께 재시작 버튼이 떠야 한다.

💡 타이머 생성 함수에서 time < 0 이라는 조건식을 가지는 if 구문 안에 위의 요구 사항들을 추가해줌

📌 6번째 요구 사항 - 코드 모음

// 타이머 관련
let time = 9;
let decreNum;

function startWorkingTimer () {
  decreNum = setInterval(function () {
    const second = time % 60;
    timer.innerHTML = `0:${second}`;
    time--;

    if (time < 0) {
      clearInterval(decreNum);

      // 6. 제한 시간 내에 모든 당근을 클릭하지 못하면
      // 1) bg.mp3 배경음이 멈춰야 한다.
      bg_mp3.pause();

      // 2) 게임 시작 버튼이 없어져야 한다.
      startBtn.style.visibility = 'hidden';

      // 3) YOU LOST 문구와 함께 재시작 버튼이 떠야 한다.
      displayResult('YOU LOST');
    }
  }, 1000);
}

7. 게임 중지 버튼을 클릭하면

  1. 게임 중지 버튼을 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) alert.wav 효과음이 들려야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) REPLAY 문구와 함께 재시작 버튼이 떠야 한다.

💡 startBtn의 이벤트 리스너 본문을 아래와 같이 수정함

startBtn.addEventListener('click', function startTimer () {
  if (document.querySelector('i[class$="stop"]') === null) {
  // 처음 startBtn 클릭하면 일어나는 일들 (2번째 요구 사항들)
  } else {
  // 중지 아이콘으로 변한 startBtn을 클릭하면 일어나는 일들 (7번째 요구 사항들)
  }

📌 7번째 요구 사항 - 코드 모음

// 2. 게임 시작 버튼을 클릭하면
startBtn.addEventListener('click', function startTimer () {
  if (document.querySelector('i[class$="stop"]') === null) {
    // 1) field 안에 당근 10개와 벌레 7마리가 랜덤한 위치에 배치되어야 한다.
    const rect = field.getBoundingClientRect();

    for (let i = 0; i < 10; i++) {
      const carrot = document.createElement('img');
      carrot.setAttribute('src', 'img/carrot.png');
      carrot.setAttribute('alt', 'carrot');

      carrot.style.left = (rect.width - 120) * Math.random() + 'px';
      carrot.style.top = (rect.height - 120) * Math.random() + 'px';

      carrot.style.width = '120px';
      field.appendChild(carrot);
    }

    for (let i = 0; i < 7; i++) {
      const bug = document.createElement('img');
      bug.setAttribute('src', 'img/bug.png');
      bug.setAttribute('alt', 'bug');

      bug.style.left = (rect.width - 80) * Math.random() + 'px';
      bug.style.top = (rect.height - 80) * Math.random() + 'px';

      bug.style.width = '80px';
      field.appendChild(bug);
    }

    // 2) 타이머가 작동해야 한다.
    timer.innerHTML = `0:10`;
    startWorkingTimer();

    // 3) 클릭 가능 횟수가 10으로 바뀌어야 한다.
    clickLimit.innerHTML = 10;

    // 4) bg.mp3 배경음이 재생되어야 한다.
    bg_mp3.play();

    // 5) 시작 버튼이 중지 버튼으로 바뀌어야 한다.
    startBtn.innerHTML = '<i class="fas fa-stop"></i>';
    
  } else { // 7. 게임 중지 버튼을 클릭하면

    // 1) bg.mp3 배경음이 멈춰야 한다.
    bg_mp3.pause();

    // 2) alert.wav 효과음이 들려야 한다.
    const alert_wav = new Audio('sound/alert.wav');
    alert_wav.play();

    // 3) 타이머가 멈춰야 한다.
    clearInterval(decreNum);

    // 4) 게임 시작 버튼이 없어져야 한다.
    startBtn.style.visibility = 'hidden';

    // 5) REPLAY 문구와 함께 재시작 버튼이 떠야 한다.
    displayResult('REPLAY ❓');
  }
});

✨ 내일 할 것

  1. 미니 게임 구현 계속
profile
능동적으로 살자, 행복하게😁

0개의 댓글