- 자바스크립트: Snake 게임 만들기 1 – 블럭 움직이기
- 자바스크립트: Snake 게임 만들기 2 – 블럭이 스스로 움직이도록 만들기, 사과(먹이) 만들기
- 자바스크립트: Snake 게임 만들기 3 – 뱀 몸체 만들기, 마무리 (完)
trail, tailLength 변수 만들기
뱀의 몸은 여러 개의 블럭으로 이루어져 있습니다. 뱀이 상하좌우로 움직일 때 이전의 위치들을 추적하는 것이 중요합니다. trail
이라는 배열을 만들어 저장하도록 하겠습니다.
현재 꼬리의 길이를 저장하는 tailLength
라는 변수도 생성하도록 하겠습니다. 초기값으로 5
를 지정하면 게임을 시작할 때 뱀의 블럭 수는 5개가 됩니다.
let positionX = 10, positionY = 10 const gridSize = 20, tileCount = 20 let velocityX = 0, velocityY = 0 let appleX = 15, appleY = 15 const trail = [] let tailLength = 5
trail 배열 갱신하기
trail
배열에 positionX
, positionY
의 위치를 객체 형태로 저장하는 원소들을 채워넣도록 하겠습니다. 단, tailLength
만큼의 원소를 저장하며, trail
배열의 길이가 tailLength
를 초과하면 shift()
를 통해 배열의 맨 앞 원소를 제거하는 작업을 해야 합니다.
function game() { // ... ctx.fillStyle = "black" ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.fillStyle = "lime" ctx.fillRect(positionX * gridSize, positionY * gridSize, gridSize - 2, gridSize - 2) trail.push({ x: positionX, y: positionY }) while(trail.length > tailLength) { trail.shift() } if(appleX === positionX && appleY === positionY) { appleX = Math.floor(Math.random() * tileCount) appleY = Math.floor(Math.random() * tileCount) } // ... }
여기까지 작성해도 표면적인 변화는 없습니다. 뱀의 몸을 그리는 렌더링 부분이 제대로 작성되지 않았기 때문입니다.
뱀 렌더링 부분 구현
game
함수에서 뱀을 그리는 부분을 아래와 같이 변경합니다.
ctx.fillStyle = "lime" // 삭제: ctx.fillRect(positionX * gridSize, positionY * gridSize, gridSize - 2, gridSize - 2) for(let i = 0; i < trail.length; i++) { ctx.fillRect(trail[i].x * gridSize, trail[i].y * gridSize, gridSize - 2, gridSize - 2) }
기존의 단일 position
을 렌더링하던 것이 for
문으로 변경되어 trail
의 배열을 순회하도록 바뀌었습니다. 사이즈 부분은 변함이 없고, 프레임 당 trail
의 배열을 따라 블럭을 여러 개 그립니다. 이렇게 하면 드디어 뱀 모양으로 이동하는 효과가 나타나게 됩니다.
그리고 뱀의 머리와 꼬리가 부딪혔을 때 게임오버가 되도록 합니다. 게임오버가 되면 tailLength
가 5인 처음 상황으로 돌아가도록 만듭니다.
for(let i = 0; i < trail.length; i++) { ctx.fillRect(trail[i].x * gridSize, trail[i].y * gridSize, gridSize - 2, gridSize - 2) if(trail[i].x === positionX && trail[i].y === positionY) { tail = 5 } }
최종 완성 코드
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Snake Game</title> | |
</head> | |
<body> | |
<canvas id="game-canvas" width="400" height="400"></canvas> | |
<script> | |
const canvas = document.getElementById("game-canvas") | |
const ctx = canvas.getContext("2d") | |
window.onload = () => { | |
document.addEventListener("keydown", keyPush) | |
// 게임 시작시 초당 15fps로 game 함수 호출 | |
setInterval(game, 1000 / 15) | |
} | |
// 뱀의 위치 | |
let positionX = 10, positionY = 10 | |
// gridSize: 가로세로 20px , tileCount = 가로세로 20개씩 총 400개의 타일 | |
const gridSize = 20, tileCount = 20 | |
// 뱀이 움직이는 방향을 설정 | |
let velocityX = 0, velocityY = 0 | |
// 사과(먹이) 위치변수 | |
let appleX = 15, appleY = 15 | |
// 뱀의 몸통을 저장하는 배열 | |
const trail = [] | |
// 현재 뱀의 길이 | |
let tailLength = 5 | |
function game() { | |
// velocity 상황에 따라 positionXY의 위치를 결정 | |
positionX += velocityX | |
positionY += velocityY | |
// 뱀 머리가 경계에 있을 떄 처리 | |
if (positionX < 0) { | |
positionX = tileCount – 1 | |
} | |
if (positionX > tileCount – 1) { | |
positionX = 0 | |
} | |
if (positionY < 0) { | |
positionY = tileCount – 1 | |
} | |
if (positionY > tileCount – 1) { | |
positionY = 0 | |
} | |
ctx.fillStyle = "black" | |
ctx.fillRect(0, 0, canvas.width, canvas.height) | |
// 뱀 그리기 | |
ctx.fillStyle = "lime" | |
for(let i = 0; i < trail.length; i++) { | |
// trail 배열만큼 그림 | |
ctx.fillRect(trail[i].x * gridSize, trail[i].y * gridSize, gridSize – 2, gridSize – 2) | |
// 게임 오버 case 1 | |
if(trail[i].x === positionX && trail[i].y === positionY) { | |
tail = 5 | |
} | |
} | |
// 게임이 진행될 때마다 positionXY를 trail 배열에 삽입 | |
trail.push({ | |
x: positionX, | |
y: positionY | |
}) | |
// 단, trail의 크기는 tailLength를 넘지 않게 | |
while(trail.length > tailLength) { | |
trail.shift() | |
} | |
// 사과 먹었을 때 | |
if(appleX === positionX && appleY === positionY) { | |
tailLength++ | |
appleX = Math.floor(Math.random() * tileCount) | |
appleY = Math.floor(Math.random() * tileCount) | |
} | |
// 사과 그리기 | |
ctx.fillStyle = "red" | |
ctx.fillRect(appleX * gridSize, appleY * gridSize, gridSize – 2, gridSize – 2) | |
} | |
// 방향키 이벤트 | |
function keyPush(evt) { | |
// arrows keys and it's left and then clockwise | |
switch (evt.keyCode) { | |
case 37: | |
velocityX = -1; | |
velocityY = 0; | |
break; | |
case 38: | |
velocityX = 0; | |
velocityY = -1; | |
break; | |
case 39: | |
velocityX = 1; | |
velocityY = 0; | |
break; | |
case 40: | |
velocityX = 0; | |
velocityY = 1; | |
break; | |
} | |
} | |
</script> | |
</body> | |
</html> |
- 자바스크립트: Snake 게임 만들기 1 – 블럭 움직이기
- 자바스크립트: Snake 게임 만들기 2 – 블럭이 스스로 움직이도록 만들기, 사과(먹이) 만들기
- 자바스크립트: Snake 게임 만들기 3 – 뱀 몸체 만들기, 마무리 (完)
1개의 댓글
쟁선 · 2021년 6월 2일 1:25 오전
감사합니다
도움이 많이 되었습니다