HTML/CSS/JavaScript λͺ¨λ μ²μλΆν° λ€μ νλ² κ΅¬νν΄λ΄
JavaScriptλ μ²μλΆν° ν¨μν νλ‘κ·Έλλ° λ°©μμ μ·¨ν¨
λͺ¨λν μ
'use strict';
let carrotCount = 10;
let bugCount = 7;
const carrotSize = 120;
const bugSize = 80;
let gameDurationTime = 10;
const startBtn = document.querySelector('.setting-startBtn');
const gameTimer = document.querySelector('.setting-timer');
const gameLimit = document.querySelector('.setting-limit');
const gameField = document.querySelector('.game-field');
const popUp = document.querySelector('.game-popUp');
const replayBtn = document.querySelector('.popUp-replayBtn');
const popUpResult = document.querySelector('.popUp-result');
const bgSound = new Audio('sound/bg.mp3');
const alertSound = new Audio('sound/alert.wav');
const carrotSound = new Audio('sound/carrot_pull.mp3');
const bugSound = new Audio('sound/bug_pull.mp3');
const winSound = new Audio('sound/game_win.mp3');
let started = false;
let timer = undefined;
let limit = carrotCount;
startBtn.addEventListener('click', () => {
if (!started) {
startGame();
} else {
stopGame();
}
});
function startGame () {
started = true;
initGame();
changePlayIconToStopIcon();
}
function stopGame () {
started = false;
finishGame('replay β', alertSound);
}
gameField.addEventListener('click', (event) => {
if (event.target.className === 'carrot') {
event.target.remove();
displayLimit(--limit);
playSound(carrotSound);
if (limit === 0) {
finishGame('YOU WON π', winSound);
}
} else if (event.target.className === 'bug') {
finishGame('YOU LOST π©', bugSound);
}
});
replayBtn.addEventListener('click', () => {
started = true;
initGame();
showStartBtn();
hidePopUp();
});
function initGame () {
placeRandomly();
startTimer();
setLimitToCarrotCount();
playSound(bgSound);
}
function finishGame (reultToShow, soundToPlay) {
stopTimer();
hideStartBtn();
showPopUp(reultToShow);
stopSound(bgSound);
playSound(soundToPlay);
}
function placeRandomly () {
gameField.innerHTML = '';
makeImg('carrot', 'img/carrot.png', carrotSize, carrotCount);
makeImg('bug', 'img/bug.png', bugSize, bugCount);
}
function makeImg(name, src, size, count) {
for (let i = 0; i < count; i++) {
const coordArray = makeRandomCoord(size);
const img = document.createElement('img');
img.setAttribute('src', src);
img.setAttribute('class', name);
img.style.left = coordArray[0] + 'px';
img.style.top = coordArray[1] + 'px';
img.style.width = size + 'px';
gameField.appendChild(img);
}
}
function makeRandomCoord (size) {
const gameFieldRect = gameField.getBoundingClientRect();
return [ gameFieldRect.left + Math.random() * ((gameFieldRect.width - size)),
gameFieldRect.top + Math.random() * ((gameFieldRect.height - size)) ];
}
function startTimer () {
let remainingTime = gameDurationTime;
displayTime(remainingTime);
timer = setInterval(() => {
if (remainingTime === 0) {
clearInterval(timer);
showPopUp('REPLAY β');
stopSound(bgSound);
playSound(alertSound);
return;
}
displayTime(--remainingTime);
}, 1000);
}
function displayTime (time) {
let minute = Math.floor(time / 60);
let second = time % 60;
gameTimer.innerHTML = `${minute}:${second}`;
}
function stopTimer () {
clearInterval(timer);
}
function setLimitToCarrotCount () {
gameLimit.innerHTML = carrotCount;
limit = carrotCount;
}
function playSound (sound) {
sound.currentTime = 0;
sound.play();
}
function stopSound (sound) {
sound.pause();
}
function changePlayIconToStopIcon () {
const icon = document.querySelector('.setting-startBtn > i');
icon.classList.add('fa-stop');
icon.classList.remove('fa-play');
}
function showStartBtn () {
startBtn.style.visibility = 'visible';
}
function hideStartBtn () {
startBtn.style.visibility = 'hidden';
}
function showPopUp (result) {
popUpResult.innerHTML = result;
popUp.style.display = 'block';
}
function hidePopUp () {
popUp.style.display = 'none';
}
function displayLimit (num) {
gameLimit.innerHTML = num
}
λͺ¨λν+Ξ± μλ£
(1) main.js
'use strict';
import PopUp from './popUp.js';
import { GameBuilder, Reason } from './game.js';
import * as Sound from './sound.js';
const gameFinishPopUp = new PopUp();
gameFinishPopUp.setReplayBtnClickListener(() => game.start());
const game = new GameBuilder()
.withGameDurationTime(10)
.withCarrotCount(10)
.withBugCount(7)
.build();
game.setStopGameListener((reason) => {
let message;
switch (reason) {
case Reason.win:
message = 'YOU WON π';
Sound.playWin();
break;
case Reason.lose:
message = 'YOU LOST π©';
Sound.playBug();
break;
case Reason.cancel:
message = 'REPLAY β';
Sound.playAlert();
break;
}
gameFinishPopUp.show(message);
});
(2) popUp.js
'use strict';
export default class PopUp {
constructor () {
this.popUp = document.querySelector('.game-popUp');
this.popUpResult = document.querySelector('.popUp-result');
this.replayBtn = document.querySelector('.popUp-replayBtn');
this.replayBtn.addEventListener('click', () => {
this.onReplayBtnClick && this.onReplayBtnClick();
this.hide();
});
}
setReplayBtnClickListener(onReplayBtnClick) {
this.onReplayBtnClick = onReplayBtnClick;
}
show (result) {
this.popUpResult.innerHTML = result;
this.popUp.style.display = 'block';
}
hide () {
this.popUp.style.display = 'none';
}
}
(3) field.js
'use strict';
import { ItemType } from './game.js';
const carrotSize = 120;
const bugSize = 80;
export default class Field {
constructor (carrotCount, bugCount) {
this.carrotCount = carrotCount;
this.bugCount = bugCount;
this.gameField = document.querySelector('.game-field');
this.gameFieldRect = this.gameField.getBoundingClientRect();
this.gameField.addEventListener('click', (event) => {
if (event.target.className === ItemType.carrot) {
this.onGameFieldCilck && this.onGameFieldCilck(ItemType.carrot);
} else if (event.target.className === ItemType.bug) {
<this.onGameFieldCilck && this.onGameFieldCilck(ItemType.bug)
}
});
}
setGameFieldClickListener (onGameFieldCilck) {
this.onGameFieldCilck = onGameFieldCilck;
}
placeRandomly () {
this.gameField.innerHTML = '';
this._makeImg(ItemType.carrot, 'img/carrot.png', carrotSize, this.carrotCount);
this._makeImg(ItemType.bug, 'img/bug.png', bugSize, this.bugCount);
}
_makeImg(name, src, size, count) {
for (let i = 0; i < count; i++) {
const coordArray = this._makeRandomCoord(size);
const img = document.createElement('img');
img.setAttribute('src', src);
img.setAttribute('class', name);
img.style.left = coordArray[0] + 'px';
img.style.top = coordArray[1] + 'px';
img.style.width = size + 'px';
this.gameField.appendChild(img);
}
}
_makeRandomCoord (size) {
return [ this.gameFieldRect.left + Math.random() * ((this.gameFieldRect.width - size)),
this.gameFieldRect.top + Math.random() * ((this.gameFieldRect.height - size)) ];
}
}
(4) sound.js
'use strict';
const bgSound = new Audio('sound/bg.mp3');
const alertSound = new Audio('sound/alert.wav');
const carrotSound = new Audio('sound/carrot_pull.mp3');
const bugSound = new Audio('sound/bug_pull.mp3');
const winSound = new Audio('sound/game_win.mp3');
export function playBackground () {
playSound(bgSound);
}
export function playAlert () {
playSound(alertSound);
}
export function playCarrot () {
playSound(carrotSound);
}
export function playBug () {
playSound(bugSound);
}
export function playWin () {
playSound(winSound);
}
export function stopBackground () {
stopSound(bgSound);
}
function playSound (sound) {
sound.currentTime = 0;
sound.play();
}
function stopSound (sound) {
sound.pause();
}
(5) game.js
'use strict';
import PopUp from './popUp.js';
import Field from './field.js';
import * as Sound from './sound.js';
export class GameBuilder {
withGameDurationTime (gameDurationTime) {
this.gameDurationTime = gameDurationTime;
return this;
}
withCarrotCount (carrotCount) {
this.carrotCount = carrotCount;
return this;
}
withBugCount (bugCount) {
this.bugCount = bugCount;
return this;
}
build () {
return new Game(this.gameDurationTime, this.carrotCount, this.bugCount);
}
}
export const Reason = Object.freeze({
win: 'win',
lose: 'lose',
cancel: 'cancel'
});
const ItemType = Object.freeze({
carrot: 'carrot',
bug: 'bug'
});
class Game {
constructor (gameDurationTime, carrotCount, bugCount) {
this.gameDurationTime = gameDurationTime;
this.carrotCount = carrotCount;
this.bugCount = bugCount;
this.started = false;
this.timer = undefined;
this.limit = this.carrotCount;
this.gameTimer = document.querySelector('.setting-timer');
this.gameLimit = document.querySelector('.setting-limit');
this.startBtn = document.querySelector('.setting-startBtn');
this.startBtn.addEventListener('click', () => {
if (!this.started) {
this.start();
} else {
this.stop(Reason.cancel);
}
});
this.ClickGameField = new Field(this.carrotCount, this.bugCount);
this.ClickGameField.setGameFieldClickListener((item) => this.onGameFieldClick(item));
this.gameFinishPopUp = new PopUp();
}
setStopGameListener (onStopGame) {
this.onStopGame = onStopGame;
}
start () {
this.started = true;
this.initGame();
this.changePlayIconToStopIcon();
}
stop (reason) {
this.started = false;
this.stopTimer();
this.hideStartBtn();
Sound.stopBackground();
this.onStopGame && this.onStopGame(reason);
}
initGame () {
this.ClickGameField.placeRandomly();
this.startTimer();
this.setLimitToCarrotCount();
Sound.playBackground();
this.showStartBtn();
}
startTimer () {
let remainingTime = this.gameDurationTime;
this.displayTime(remainingTime);
this.timer = setInterval(() => {
if (remainingTime === 0) {
clearInterval(this.timer);
this.onStopGame && this.onStopGame(Reason.cancel);
Sound.stopBackground();
Sound.playAlert();
return;
}
this.displayTime(--remainingTime);
}, 1000);
}
displayTime (time) {
let minute = Math.floor(time / 60);
let second = time % 60;
this.gameTimer.innerHTML = `${minute}:${second}`;
}
stopTimer () {
clearInterval(this.timer);
}
setLimitToCarrotCount () {
this.gameLimit.innerHTML = this.carrotCount;
this.limit = this.carrotCount;
}
changePlayIconToStopIcon () {
const icon = document.querySelector('.setting-startBtn > i');
icon.classList.add('fa-stop');
icon.classList.remove('fa-play');
}
showStartBtn () {
this.startBtn.style.visibility = 'visible';
}
hideStartBtn () {
this.startBtn.style.visibility = 'hidden';
}
displayLimit (num) {
this.gameLimit.innerHTML = num
}
onGameFieldClick (item) {
if (!this.started) {
return;
}
if (item === ItemType.carrot) {
event.target.remove();
Sound.playCarrot();
this.displayLimit(--this.limit);
if (this.limit === 0) { // limit λμ μ gameLimit.innerHTML μ°λ©΄ μ μ λλ κ±ΈκΉ? π₯π₯π₯
this.stop(Reason.win);
}
} else if (item === ItemType.bug) {
this.stop(Reason.lose);
}
}
}
μ μ λ³μ μ μΈ μμ (κ°μ μ°Έκ³ )
gameField ν΄λ¦ μ΄λ²€νΈ 리μ€λ μ½λ°± ν¨μ μ€ μλ μ½λμ if 쑰건μμμ limit λμ gameLimit.innerHTMLλΌκ³ μ°λ©΄ μλν λλ‘ μλνμ§ μλλ€. limitλ₯Ό μ¨μ ν΄κ²°μ νμ§λ§, gameLimit.innerHTMLμ μ μ λλ κ±ΈκΉ. πββοΈ
if (limit === 0) {
stopTimer();
hideStartBtn();
showPopUp('YOU WON π');
stopSound(bgSound);
playSound(winSound);
}
finish ν¨μμ μΈμλ₯Ό, κ²μ κ²°κ³Ό 문ꡬμμ true/falseλ‘ λ°κΎΈκ³ game.js νμΌμ setStopGameListenerλ₯Ό μμ±νλ κ²μ ν¬ν¨ν μΌλ ¨μ κ³Όμ λ€μ λΉΌλ¨Ήμλ€. μ΄λ κ² ν΄μ£Όμ§ μμλ λͺ¨λ μ€λ₯ μμ΄ μ μ μλνκ³ λͺ¨λνλ κ°λ₯νλ°, μ΄λ κ² ν΄μ£Όλ 건 μ μ§Β·λ³΄μλ₯Ό μ½κ² νκΈ° μν¨μΈκ°. μ½λλ μ΄ν΄λ₯Ό ν΄μ μμ±μ μ΄λ ΅μ§ μμλ° μ μ΄μ μ΄λ κ² ν΄μΌκ² λ€λ μκ°μ μ΄λ»κ² ν μ μμκΉ. πββοΈ
game.jsμμ λΉλ ν¨ν΄ μμ± μ, ν¨μ μμ return this
λ₯Ό μ¨μ£Όλ μ΄μ
λ°°μ΄μ map()μ΄λ reduce()λ₯Ό μ¬μ©νλ©΄ λ°°μ΄μ΄ returnλλ―λ‘, μ¬κΈ°μ λ©μλλ₯Ό μ°μμ μΌλ‘ κ³μ μ¬μ©ν μ μλ€. μ΄μ λμΌν ν¨κ³Όλ₯Ό λ΄κΈ° μν¨μ΄λ€. μλ μ½λμ²λΌ μμ±ν μ μλ€.
// main.js δΈ
const game = new GameBuilder()
.withGameDurationTime(10)
.withCarrotCount(10)
.withBugCount(7)
.build();
μ΄λ€ νμΌμμ export defaultκ° μμΌλ©΄, λ€λ₯Έ νμΌμμ import λ€μ {}λ₯Ό λ°λμ μ¨μ€μΌ νλ€.
gamefieldμ μκ΄(μ΄λ―Έμ§ λλ€ λ°°μΉ, μ΄λ―Έμ§ ν΄λ¦)μ΄ μλκΈ° λλ¬Έμ Field ν΄λμ€μ λ©μλλ‘ μ μ΄μ£Όμ§ μμ ν¨μλ€(displayLimit, finishGame, playCarrot)κΉμ§ λ€λ₯Έ js νμΌμ κ±°μ³ μ²λ¦¬νκΈ° μν΄ μ μ΄μ€ κ²
μ΄λ€ κ²½μ°μ μλμ κ°μ μμ μ½λλ₯Ό μ¨ λ£λμ§ ν·κ°λ Έλλ°, μ λ΄μ©μ²λΌ μ΄ν΄νλ€. κ·Όλ° μΌλ°νν΄μ κΈλ‘ μ€λͺ
νκΈ°κ° μ΄λ ΅λ€
this.onGameFieldCilck && this.onGameFieldCilck('carrot');
// field.js μμ
this.gameField.addEventListener('click', (event) => {
if (event.target.className === ItemType.carrot) {
this.onGameFieldCilck && this.onGameFieldCilck(ItemType.carrot);
} else if (event.target.className === ItemType.bug) {
this.onGameFieldCilck && this.onGameFieldCilck(ItemType.bug)
}
});
// game.js μμ
onGameFieldClick (item) {
if (!this.started) { // startedκ° falseμ΄λ©΄, ν΄λ¦λμ§ μλλ‘
return;
<}
if (item === ItemType.carrot) {
event.target.remove();
Sound.playCarrot();
this.displayLimit(--this.limit);
if (this.limit === 0) {
this.stop(Reason.win);
}
} else if (item === ItemType.bug) {
this.stop(Reason.lose);
}
}
μ΄μ κΉμ§λ μ΄λ»κ²λ μ€λ₯ μμ΄ μλνκ² λ§λλ κ²μλ§ μ κ²½μ μ¨μλλ°, κ·Έκ² μ λΆκ° μλμ λκΌλ μ€μ΅μ΄μλ€. κ·Έλμ μ μ°¨ν νλ‘κ·Έλλ°μ μ΅μν΄μ Έ κ°λ¨νκ³ μ½κ² μΈ μ μλ μ½λλ₯Ό μκΎΈ λμ λμ μ΄λ ΅κ² νννλ κ±° κ°λ€.
μ¬μ€ ν¨μν νλ‘κ·Έλλ°μ κ±±μ νλ κ²λ³΄λ€ μ΄ν΄κ° μ λΌμ μ κΉ μ λ¬μλ€. κ·Έλ°λ° μκ°λ λͺ»νλ, κ·Έ μ κΉμ§ μ΄λ° κ² μ‘΄μ¬νλμ§λ λͺ°λλ 'λͺ¨λν'λΌλ λ§μ§λ§ λ¨κ³μμ κ½€λ μ λ₯Ό λ¨Ήμλ€. μ²μμΌλ‘ ν루 μ¨μ’ μΌμ μ¨λ κΉλνκ² μ΄ν΄κ° μ λΌμ μ κΉ μ’μ νκΈ°λ νλ€. κ·Έλλ μ΄λ»κ²λ κ²°κ΅μ μ΄ν΄νλ€.
λ€λ§, μ΄ μ€ λͺ νλ‘λ μ¨μ ν λ΄ κ²μ΄ λμ΄ μμμ§ λͺ¨λ₯΄κ² λ€. μμ μ¨λμ κ²μ²λΌ μ΄ μ½λ μ체λ μ΄ν΄νμ§λ§, μ¬κΈ°μ μ΄λ»κ² μ΄λ° μμΌλ‘ μκ°ν μ μμκΉ, μΆμ λΆλΆμ΄ μλ€. λ€λ₯Έ μμ μμ κ°μ μν©μ λ§λ¬μ λ λ΄κ° κ³Όμ° μ€μ€λ‘ μ κ±Έ μκ°ν΄μ μ μ©ν μ μμκΉ μΆκΈ°λ νλ€.
κ·Έλλ μ΄λ² μ€μ΅ μ κΉμ§λ λκ° μκΈ΄ μλλ° μ΄κ² μ λλ‘ μλ κ±΄μ§ μ΄λ€ κ±΄μ§ μ’μ²λΌ λ§μ°ν κ°μ΄ μλ ν¨μλ μμ΄μ μ‘°κΈμ΄λλ§ μΉν΄μ§ λ―ν λλμ΄ λλ κ² μ΄λ² μ€μ΅μ κ°μ₯ ν° μν κ°λ€.
λͺ¨λν+Ξ± κ°μ κ²½μ°λ μ΄μ κΉμ§λ§ ν΄λ ννΈνλ μ§μ λλ¬Έμ λΆλͺ ν λ°°μ°κΈ΄ νμ§λ§ λ΄ κ²μ΄ μλ λλμ΄ μμλλ°, μ€λ λ€μ μ²μλΆν° λκΉμ§ μ€μ€λ‘ ꡬνν΄ λ³΄λ©΄μ λΉλ‘μ λ΄κ° μ΄λ€ λΆλΆμ μ΄λ»κ² μ΄ν΄νκ³ μλμ§ λλ¦λλ‘ μ 리νλ μκ°μ κ°μ§ μ μμλ€.
μ΄λ‘μ¨ λΈλΌμ°μ 101 κ°μλ μκ°μ νλ€. μμΌλ‘ ν΄μΌ ν κ²λ€μ μ μ΄λ΄€λ€. μ΄λ λ€ν μ€μ΅μ΄ μμ΄μ μ΄λ‘ 곡λΆμ ν¨κ» λ―Έλ νλ‘μ νΈλ₯Ό κ²Έν΄μΌ ν κ±° κ°λ€.
λΈλΌμ°μ 101 κ°μ λ³΅μ΅ / νλ‘κ·Έλλ¨Έμ€ λ¬Έν & μλ£κ΅¬μ‘° μκ³ λ¦¬μ¦ κ°μ μκ° / git κ°μ μκ° / νλ‘κ·Έλλ° μ± μ½κΈ° / 리μ‘νΈ κ°λ κ°μ μκ°
λΈλΌμ°μ 101 κ°μ 볡μ΅
νλ‘κ·Έλλ¨Έμ€ λ¬Έν
μλ£κ΅¬μ‘° μκ³ λ¦¬μ¦ κ°μ μμ보기