이 글을 먼저 읽어보는걸 추천 드리고, 초보자라면 첫 번째 게임부터 따라서 만들어 보는걸 추천합니다.
이번에는 뱀(Snake) 게임 입니다.
이런결과물이 나옵니다.
앞선 게임들과 동일하게 CSS는 최소화 합니다.
원하는 테마를 생각하고 만들어보는게 좋은 연습이 될 것 같습니다.
저는 고흐의 시선(Gogh's Vision)으로 바꿔서 만들었습니다.
여기서는 처음 뱀 게임의 코드를 소개하고, 주석으로 각각 설명을 달았습니다.
사용하는 에디터(VSCode, Sublime 등)에 복사해서 보면 훨씬 보기 싶습니다.
고흐의 시각(Gogh's Vision)은 Github에서 코드를 확인할 수 있습니다.
링크 ▶ https://github.com/ermis0704/Goghs-Vision
코딩에 들어가기전 준비물
snake.html / snake.css / snake.js 만 있으면 됩니다.
밑의 함수를 사용합니다
미리 알고 있으면 편하게 볼 수 있을겁니다.
• querySelector()
• addEventListener()
• setInterval()
• keyCodes
• pop()
• unshift()
• push()
• classList.contains()
• classList.add()
• classList.remove()
그럼 HTML부터 시작합니다!
HTML
<html>
<head>
<meta charset="utf-8">
<!--스타일시트, 자바스크립트 연결-->
<script src="snake.js"></script>
<link rel="stylesheet" href="snake.css">
<title>Snake Game</title>
</head>
<body>
<!--게임시작 버튼-->
<button class='start'>Start/Restart</button>
<div class='score'>Score:<span>0</span></div>
<!-- 전체 100개의 div필요, 10x10 크기 -->
<div class='grid'>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</body>
</html>
CSS
//게임 판을 flex, 넓이, 높이를 정해 만든다
.grid {
display:flex;
width: 200px;
height: 200px;
flex-flow: row wrap;
border: solid;
}
//앞에서 만든 div 100개의 칸 크기 지정
.grid div{
width: 20px;
height: 20px;
}
//뱀의 색상
.snake {
background-color: blue;
}
사과 색상
.apple {
background-color: red;
}
JAVASCRIPT
//기본 HTML이 구성되면 실행되도록 모든 자바스크립트 코드를 감싼다
document.addEventListener('DOMContentLoaded', () =>{
//게임의 칸 100개 가져오기
const squares = document.querySelectorAll('.grid div');
//스코어 가져오고
const scoreDisplay = document.querySelector('.score span');
//버튼 가져오기
const startBtn = document.querySelector('.start');
//밑으로 한 칸 가기 위한 숫자. 한 줄에 div가 10개 있기때문에 1칸 밑으로 가려면 10을 더해주면 된다.
const width = 10;
//사과 위치가 저장될 곳
let appleIndex = 0;
//뱀의 시작 위치
let currentSnake = [2, 1, 0]
//방향을 정하는 변수
let direction = 1;
//점수 변수
let score = 0;
//스피드 변수, 점점 빨라 질것이기 때문에 1보다 낮은 0.9 사용
let speed = 0.9;
//뱀을 정해진 시간마다 움직이게 할 변수
let intervalTime = 0;
//setInterval을 위한 변수
let interval = 0;
//게임시작시 실행될 함수
function startGame() {
//이 함수 주로 값들을 기본값으로 바꿔주는 내용을 가지고 있다.
//처음 시작할 때는 괜찮지만, 재시작을 하면 남아있는 사과, 뱀을 없애준다.
currentSnake.forEach(index => squares[index].classList.remove('snake'))
squares[appleIndex].classList.remove('apple');
clearInterval(interval);
score = 0;
//사과배치 함수 실행
randomApple();
direction = 1;
scoreDisplay.innerHTML = score;
intervalTime = 1000;
currentSnake = [2, 1, 0];
currentIndex = 0;
currentSnake.forEach(index => squares[index].classList.add('snake'));
//intervalTime 즉 1초마다 moveOutComes() 함수를 실행한다.
interval = setInterval(moveOutComes, intervalTime);
}
//밑의 control() 함수부터 보는 걸 추천합니다
//중요한 뱀의 움직임을 담당할 함수
function moveOutComes() {
//벽에 부딪히면 게임이 게임이 끝나도록 하는 if문
if(
//뱀이 바닥을 부딪혔을때
//맨 밑에 div 10개는 90부터 99, 여기에 10을 더하면 100~109 즉 div 밖이다
//그리고 방향이 밑을 향하고 있을때 성립할 때 죽는다.
(currentSnake[0] + width >= (width * width) && (direction === width)) ||
//오른쪽 벽에 부딪혔을때
//div의 맨 오른쪽은 9, 19, 29, ... 99,
//여기에 나머지를 구하는 '%'를 사용해서 값이 9(width -1)가 나오고 &&
//방향이 오른쪽(1)이면 죽음
(currentSnake[0] % width === width -1 && direction === 1) ||
//같은 방식으로 왼쪽,
(currentSnake[0] % width === 0 && direction === -1) ||
//위의 벽도 부딪히면 죽는다
(currentSnake[0] - width < 0 && direction === -width) ||
//한 가지더 뱀의 머리가 뱀의 몸통을 터치하면 죽는 방식도 넣어둔다.
squares[currentSnake[0] + direction].classList.contains('snake')
) {
//위의 if문에 해당되면 게임을 중지(종료)
return clearInterval(interval);
}
//↓↓↓여기부턴 뱀이 움직이는 동작
//시작시 뱀은 [2,1,0] 즉 div 0, 1, 2에 있다.
//tail 변수에 pop()으로 0을 떼어서 넣고, 뱀의 배열도 [2, 1]로 만든다
const tail = currentSnake.pop();
//div의 tail 자리인 0에 뱀 클래스를 제거함으로 화면에 없어진다
squares[tail].classList.remove('snake');
//뱀의 배열 맨 앞에 머리와 방향(direction)을 더해 unshift()로 집어넣는다.
//예를들어 오른쪽으로 가면 현재 머리(2)와 방향(1)을 더해 3을 집어넣어 [3, 2, 1]이 된다
//아직 배열에서 넣었을 뿐, 화면에 표시하지는 않았다.
currentSnake.unshift(currentSnake[0] + direction);
//뱀의 머리가 사과를 만났을 때 if문
//머리가 사과를 가진 div에 도달 했으면 실행
if(squares[currentSnake[0]].classList.contains('apple')) {
//우선 사과를 div에서 없애 화면에 사라지게 하고
squares[currentSnake[0]].classList.remove('apple');
//div의 tail이 있던 자리에 뱀을 하나 추가한다
squares[tail].classList.add('snake');
//뱀 배열에도 tail자리를 넣어준다
currentSnake.push(tail);
//새로 사과 배치
randomApple()
//점수를 1점 올리고
score++;
//스코어에 표시
scoreDisplay.textContent = score;
//게임을 잠깐 중단을 하고
clearInterval(interval);
//1000이었던 intervalTime에 앞에서 정한 0.9의 speed 값을 곱해 900로 만든다.
//1초에서 0.9초로 줄어든다
intervalTime *= speed;
//빨라진 시간으로 현재 함수인 moveOutComes()을 실행 -> 뱀이 빨리 움직인다
interval = setInterval(moveOutComes, intervalTime);
}
//앞서 unshift()로 넣었던 머리 부분에 div에 뱀의 클래스를 추가함으로 화면에 표시
squares[currentSnake[0]].classList.add('snake');
}
//사과를 랜덤하게 배치하는 함수
function randomApple() {
//처음 한번 실행해야 되서, do {} while 반복문을 사용
do {
//div의 길이(100개)와 0~1의 랜덤숫자를 곱하고, Math.floor로 내림해준다.
//그래서 나올 수 있는 수는 0~99
appleIndex = Math.floor(Math.random() * squares.length);
//사과 인덱스가 snake 클래스를 가지고 있으면 또 실행된다.
//결국 snake 클래스를 가지고 있지않은 div를 찾기 위함이다
} while(squares[appleIndex].classList.contains('snake'));
//나온 위치에 사과를 표시
squares[appleIndex].classList.add('apple');
}
//게임키를 받아서 뱀의 방향을 정해주는 함수
//키보드의 모든 문자, 숫자에는 번호가 정해져있다.
//사이트 https://keycode.info에서 확인가능
function control(e) {
//오른쪽
//오른쪽의 code는 39다 그래서 39가 눌리면 방향을 1로 바꿔준다.
//밑의 위, 왼쪽, 아래도 같은 방식이다.
if(e.keyCode === 39) {
direction = 1;
//up
} else if(e.keyCode === 38) {
direction = -width;
//left
} else if(e.keyCode === 37) {
direction = -1;
//down
} else if(e.keyCode === 40) {
direction = +width;
}
}
//키가 눌렸다 올라갈 때 마다 control() 함수가 실행되서 방향(direction)이 바뀐다.
document.addEventListener('keyup', control);
//게임시작 버튼을 클릭되면 startGame() 함수가 실행
startBtn.addEventListener('click', startGame);
})
'Web Dev > JavaScript :: 자바스크립트' 카테고리의 다른 글
[Javascript] 즉각 실행되는 IIFE (0) | 2020.06.21 |
---|---|
[Javascript] 클로저 closure 이란? (0) | 2020.06.21 |
자바스크립트로 게임 만들기 (2/7) 모기 잡기 (0) | 2020.05.22 |
[Javascript] 반올림 함수 Math.round() (0) | 2020.04.27 |
[Javascript] Arguments 배열로 만드는 3가지 방법 (0) | 2020.04.21 |