joyful
[Javascript] 가위바위보 게임 본문
이 글은 유튜브 제로초님의 가위바위보 게임 강좌를 참고하여 작성한 글입니다.
자바스크립트로 가위바위보 게임을 만들어 보았습니다.
<!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>가위바위보 게임</title>
<style>
#computer {
width: 142px;
height: 200px;
}
</style>
</head>
<body>
<div id="computer"></div>
<div class="rsp-wrap">
<button id="scissors" class="btn">가위</button>
<button id="rock" class="btn">바위</button>
<button id="paper" class="btn">보</button>
</div>
<div id="score"></div>
</body>
</html>
<script>
const $computer = document.querySelector("#computer");
const $score = document.querySelector("#score");
const $rock = document.querySelector("#rock");
const $scissors = document.querySelector("#scissors");
const $paper = document.querySelector("#paper");
const IMG_URL = './img/rsp.png';
$computer.style.background = `url(${IMG_URL}) -440px 0`;
$computer.style.backgroundSize = 'auto 200px';
//객체(rsp의 X좌표라는 공통점으로 묶기)
const rspX = {
scissors: '0', // 가위
rock: '-220px', // 바위
paper: '-440px', // 보
};
//이미지 변환
let computerChoice = 'scissors';
const changeComputerHand = () => {
if (computerChoice === 'rock') { // 바위면
computerChoice = 'scissors'; //데이터는 가위로 바뀌고
} else if (computerChoice === 'scissors') { // 가위면
computerChoice = 'paper'; //데이터는 보로 바뀌고
} else if (computerChoice === 'paper') { // 보면
computerChoice = 'rock'; //데이터는 바위로 바뀌고
}
$computer.style.background = `url(${IMG_URL}) ${rspX[computerChoice]} 0`; //화면도 바뀌고
$computer.style.backgroundSize = 'auto 200px'; //사이즈를 다시 선언하지 않으면 리셋되기 때문에 반드시 다시 선언해줘야 함
}
let intervalId = setInterval(changeComputerHand, 100);
const scoreTable = { //규칙 찾기 위해 가위, 바위, 보를 숫자로 변환
rock: 0,
scissors: 1,
paper: -1,
};
let clickable = true;
let score = 0;
const clickButton = (event) => {
if (clickable) {
//버튼 눌렀을 때 화면 멈춤
clearInterval(intervalId);
clickable = false; //버그 수정:1초 동안 버튼이 클릭되지 않게 -버그:여러번 클릭하면서 interval 값이 중복저장되어 빨리 움직이고 버튼 눌렀을 때 멈추지 않음
//타이머 설정해서 설정시간(1초) 지난 후 재실행
setTimeout(() => {
clickable = true; //버그 수정:1초 뒤 버튼 다시 클릭 되게
intervalId = setInterval(changeComputerHand, 100);
}, 1000);
// 점수 계산 및 화면 표시
const myChoice = event.target.textContent === '바위' //내 선택(텍스트)이 바위면 데이터도 바위
? 'rock'
: event.target.textContent === '가위'
? 'scissors'
: 'paper';
const myScore = scoreTable[myChoice]; //내 점수
const computerScore = scoreTable[computerChoice]; //컴퓨터 점수
const diff = myScore - computerScore; //내 점수에서 컴퓨터 점수를 빼서 나오는 점수대로 승부 결정
let message;
// 2, -1은 승리조건이고, -2, 1은 패배조건
if ([2, -1].includes(diff)) {
score += 1;
message = '이겼습니다!';
} else if ([-2, 1].includes(diff)) {
score -= 1;
message = '졌습니다!';
} else {
message = '비겼습니다!';
}
$score.textContent = `${message}`;
}
};
$rock.addEventListener('click', clickButton);
$scissors.addEventListener('click', clickButton);
$paper.addEventListener('click', clickButton);
</script>
만들다 보니 문제점이 하나 있었습니다.
이미지를 변환하는 코드에서 스크립트로 background 이미지의 position 스타일을 지정했는데,
이 게임은 간단한 프로그램이라서 괜찮지만, 이 경우가 많아지면 성능 저하의 원인이 될 수 있습니다.
따라서 스크립트는 스크립트에만! 스타일은 스타일에만! 지정해주는 것이 좋습니다.
그래서 미리 지정할 수 있는 스타일은 스타일에만 지정한 후,
클래스명을 추가했다 빼주는 방식으로 변경해보았습니다.
바로 이렇게요!
전체적인 코드 보여드리고 세부적으로 변경된 부분 정리하겠습니다,
lines (90 sloc) 3.39 KB
<!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>가위바위보 게임</title>
<style>
#computer {
width: 142px;
height: 200px;
background: url(https://i.postimg.cc/7PM3vTRh/rsp.png) -440px 0;
background-size: auto 200px;
}
#computer.is-scissors {
background-position: 0;
}
#computer.is-rock {
background-position: -220px 0;
}
#computer.is-paper {
background-position: -440px 0;
}
</style>
</head>
<body>
<div id="computer" class="is-scissors"></div>
<div class="rsp-wrap">
<button id="scissors" class="btn">가위</button>
<button id="rock" class="btn">바위</button>
<button id="paper" class="btn">보</button>
</div>
<div id="score"></div>
</body>
</html>
<script>
const $computer = document.querySelector("#computer");
const $score = document.querySelector("#score");
const $rock = document.querySelector("#rock");
const $scissors = document.querySelector("#scissors");
const $paper = document.querySelector("#paper");
//이미지 변환
let prevComputerChoice;
let computerChoice = 'scissors';
const changeComputerHand = () => {
prevComputerChoice = computerChoice;
if (computerChoice === 'rock') { // 바위면
computerChoice = 'scissors'; //데이터는 가위로 바뀌고
} else if (computerChoice === 'scissors') { // 가위면
computerChoice = 'paper'; //데이터는 보로 바뀌고
} else if (computerChoice === 'paper') { // 보면
computerChoice = 'rock'; //데이터는 바위로 바뀌고
}
$computer.classList.remove(`is-${prevComputerChoice}`);
$computer.classList.add(`is-${computerChoice}`);
}
let intervalId = setInterval(changeComputerHand, 100);
const scoreTable = { //규칙 찾기 위해 가위, 바위, 보를 숫자로 변환
rock: 0,
scissors: 1,
paper: -1,
};
let clickable = true;
let score = 0;
const clickButton = (event) => {
if (clickable) {
//버튼 눌렀을 때 화면 멈춤
clearInterval(intervalId);
clickable = false; //버그 수정:1초 동안 버튼이 클릭되지 않게 -버그:여러번 클릭하면서 interval 값이 중복저장되어 빨리 움직이고 버튼 눌렀을 때 멈추지 않음
//타이머 설정해서 설정시간(1초) 지난 후 재실행
setTimeout(() => {
clickable = true; //버그 수정:1초 뒤 버튼 다시 클릭 되게
intervalId = setInterval(changeComputerHand, 100);
}, 1000);
// 점수 계산 및 화면 표시
const myChoice = event.target.textContent === '바위' //내 선택(텍스트)이 바위면 데이터도 바위
? 'rock'
: event.target.textContent === '가위'
? 'scissors'
: 'paper';
const myScore = scoreTable[myChoice]; //내 점수
const computerScore = scoreTable[computerChoice]; //컴퓨터 점수
const diff = myScore - computerScore; //내 점수에서 컴퓨터 점수를 빼서 나오는 점수대로 승부 결정
let message;
// 2, -1은 승리조건이고, -2, 1은 패배조건
if ([2, -1].includes(diff)) {
score += 1;
message = '이겼습니다!';
} else if ([-2, 1].includes(diff)) {
score -= 1;
message = '졌습니다!';
} else {
message = '비겼습니다!';
}
$score.textContent = `${message}`;
}
};
$rock.addEventListener('click', clickButton);
$scissors.addEventListener('click', clickButton);
$paper.addEventListener('click', clickButton);
</script>
먼저, html에서 computer 박스에 'is-scissors'라는 클래스명을 붙였습니다.
컴퓨터의 데이터가 가위일 때 가위 이미지가 스크립트로 불러오도록 말이죠!
그리고 스타일에서 배경이미지의 경로와 사이즈를 선언하고
각각의 'is-~'클래스가 붙을 때 가위, 바위, 보의 이미지 위치를 선언했습니다.
<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>가위바위보 게임</title>
<style>
#computer {
width: 142px;
height: 200px;
background: url(https://i.postimg.cc/7PM3vTRh/rsp.png) -440px 0;
background-size: auto 200px;
}
#computer.is-scissors {
background-position: 0;
}
#computer.is-rock {
background-position: -220px 0;
}
#computer.is-paper {
background-position: -440px 0;
}
</style>
</head>
스크립트에서는 배경이미지의 경로와 사이즈, position에 관련된 스타일을 모두 지웠습니다.
그리고 클래스명을 지웠다 추가할 수 있는
classList.add 와 classList.remove라는 함수를 사용했습니다!
//이미지 변환
let prevComputerChoice;
let computerChoice = 'scissors';
const changeComputerHand = () => {
prevComputerChoice = computerChoice;
if (computerChoice === 'rock') { // 바위면
computerChoice = 'scissors'; //데이터는 가위로 바뀌고
} else if (computerChoice === 'scissors') { // 가위면
computerChoice = 'paper'; //데이터는 보로 바뀌고
} else if (computerChoice === 'paper') { // 보면
computerChoice = 'rock'; //데이터는 바위로 바뀌고
}
$computer.classList.remove(`is-${prevComputerChoice}`);
$computer.classList.add(`is-${computerChoice}`);
}
let intervalId = setInterval(changeComputerHand, 100);
`is-rock` `is-paper` `is-scissors`라는 클래스들을 지웠다 추가하여 이미지의 위치가 interval되게 한다는 의미이죠!
그런데 여기서!
이미 선언된 데이터가 지워져야만 새로운 데이터가 읽히며 가위, 바위, 보 이미지가 변경이 됩니다.
따라서, computerChoice라는 컴퓨터의 데이터가 바뀌기 전에 이전 데이터를 저장하고 이를 다시 부르는 저장소가 필요합니다!
바로 새로운 변수를 만드는 것이죠!
이 저장소를 'prevComputerChoice'라는 변수로 선언하고, classList.remove함수로 지워지도록 했습니다.
그럼 이전 데이터는 지워지고, 새로운 데이터가 추가되는 동작이 반복되며 가위, 바위, 보 이미지의 위치가 변경되겠죠!
'prevComputerChoice=computeChoice'
이 변수는 이미지가 변환되는 동작에 모두 실행되어야 하기 때문에 전역변수로 선언해야 합니다.
따라서 if문 위에 전체적으로 실행되도록 작성해야 합니다.
'Javascript' 카테고리의 다른 글
[Javascript] split(), map(), 람다식 함수 (2) | 2023.07.15 |
---|---|
Javascript 개념정리 - 폼과 자바스크립트 & 브라우저 객체모델 (2) | 2023.07.01 |
Javascript 개념 정리4 - 기본타입 (0) | 2023.01.12 |
Javascript 개념 정리3 - 변수 (0) | 2023.01.09 |
Javascript 개념 정리2 - 출력방법 (0) | 2023.01.09 |