첫 번째 프로젝트 - BLACK MAMBA (2)

JooYong Lee·2021년 11월 21일
0

BLACK MAMBA

목록 보기
2/5
post-thumbnail

앞서 만들었던 부분에서는 뱀이 벽이나 스스로에게 끼여서 멈추는 현상이 있었다.

이를 해결하기위해 제자리에서 일정 횟수 이상 전진할 방향을 찾지 못하면 처음 위치로 돌아가도록 했다.

또 보석을 먹으면 뱀이 늘어나도록 해야했기 때문에 코드를 거의 다 새로 작성했다.

우선 작동 방식을 바꿨다.
화면에 보여질 필드와 뱀을 기록할 2차원 배열을 만든 뒤에 테스트용 버튼을 하나 만들어서 버튼을 클릭할 때 마다 뱀이 한 마리씩 추가되도록 했다.

만들고 사용한 함수들은 다음과 같다.
makeFiled() : 화면에 보여질 25*25 짜리 필드를 만든다.
addSnake() : 뱀을 한 마리 추가하는 함수다. 뱀이 추가될 위치에 다른 뱀이 지나고 있는지 확인하면서 아무것도 없을 때 들어가도록 한다.
moveSnake() : 아무것도 없어 뱀 추가가 가능해지면 실행된다.
forward() : 뱀이 앞으로 전진하는 함수이다.
turn() : 더 이상 앞으로 갈 수 없거나, 일정 거리 앞으로 전진했을 때 방향을 바꿔준다.
resetSnake() : 벽이나, 스스로 또는 다른 뱀에게 끼이는 일이 생기면 처음 위치로 되돌려준다.

먼저 html과 board, field 그리고 그외 필요한 변수들

<!DOCTYPE html>
<html lang="en">
<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>Black Mamba</title>
</head>
<body>
    <table border="1" width="500" height="500" id="game-board"></table>
    <button id="add-snake">뱀 추가</button>
    <span id="mamba"></span>
    <script src="js/blmam.js"></script>
</body>
</html>
//board 생성
const board = new Array(25);
for (let i = 0; i<25; i++){
    board[i] = new Array(25);
}
for (let i=0;i<25;i++){
    for (let j=0; j<25; j++){
        board[i][j] = 0;
    }
}
//뱀 마리 수 표시용
const mamba = document.getElementById("mamba");
let mambaCount = 0;

//동서남북 체크에 쓰일 방향들
const dx = [0, -1, 0, 1]
const dy = [1, 0, -1, 0]

//뱀 추가 버튼
const button = document.getElementById("add-snake");

//field table생성
function makeField(){
    const gameboard = document.getElementById("game-board");
    
    for (let i = 0; i<25; i++){
        const tr = document.createElement("tr");
        for (let j = 0; j<25; j++){
            const td = document.createElement("td");
            td.id = `${i},${j}`;
            tr.appendChild(td);
        }
        gameboard.appendChild(tr);
    }
}

아래는 뱀을 추가해주는 함수

function addSnake(){
    mambaCount += 1;
    mamba.innerText = mambaCount;
    const snake = [];
    for (let i = 0; i < 9; i++){
        snake.push([24, i])
    } //왼쪽 하단에 뱀을 만들 것이다.
    
    let checkEmpty = setInterval(function(){
        let check = true;
        for (let i = 0; i<9; i++){
            if (board[24][i] === 1){
                check = false;
            }
        }
        if (check){
            clearInterval(checkEmpty);
            moveSnake(snake);
        }
    }, 100);
  	//왼쪽 하단 부분이 비어있는지를 확인하면서 새로운 뱀을 놓을 수 있을 때 까지 반복해준다. setInterval을 사용한 이유는 while문으로 했을 때 검사 속도가 너무 빨라서 아예 작동 자체가 멈춰버리는 것 같았다.
}

새로운 뱀을 놓을 수 있는 조건이 갖춰지면 moveSnake()를 호출

//방향 0:좌, 1:하, 2:우, 3:상
function moveSnake(snake){
    let now_dir = 0;
    for (let i = 0; i<9; i++){
        document.getElementById(`24,${i}`).style.backgroundColor = "black";
        board[24][i] = 1;   
    }
    
    let forward_rnd = Math.floor(Math.random() * 10) % 3 + 3;
    let count = 0;
    let moving = setInterval(function() {
        let move = forward(snake, now_dir, count, forward_rnd);
        snake = move[0];
        now_dir = move[1];
        count = move[2];
        forward_rnd = move[3];
        if (snake === -1){
            clearInterval(moving);
            addSnake();
        }
    }, 100);
}

왼쪽 하단에 뱀을 그리고 앞으로 전진하는 forward함수를 만들고 호출해주었다. 이 함수는 뱀의 위치 정보와 현재 쳐다보고 있는 방향, 앞으로 몇 칸 째 움직이고 있는지, 앞으로 몇 칸을 갈 것인지를 받는다.

function forward(snake, now_dir, count, forward_rnd){
    count = count + 1;
    if (count === forward_rnd){
        const nextDir = turn(snake);
        forward_rnd = Math.floor(Math.random() * 10) % 3 + 3;
        if (nextDir === -1){
            return [resetSnake(snake), 0, 0, forward_rnd];
        }
        return [snake, nextDir, 0, forward_rnd];
    }
    let snakeHead = snake[snake.length - 1];
    const nextX = snakeHead[0] + dx[now_dir];
    const nextY = snakeHead[1] + dy[now_dir];
    if ((nextX>=0 && nextX<25) && (nextY>=0 && nextY<25) && board[nextX][nextY] === 0){
        snake.push([nextX,nextY]);
        document.getElementById(`${nextX},${nextY}`).style.backgroundColor = "black";
        board[nextX][nextY] = 1;
        const snakeTail = snake.shift();
        document.getElementById(`${snakeTail[0]},${snakeTail[1]}`).style.backgroundColor = "white";
        board[snakeTail[0]][snakeTail[1]] = 0;
        return [snake, now_dir, count, forward_rnd];
    }else{
        const nextDir = turn(snake);
        forward_rnd = Math.floor(Math.random() * 10) % 3 + 3;
        if (nextDir === -1){
            return [resetSnake(snake), 0, 0, forward_rnd];
        }
        return [snake, nextDir, 0, forward_rnd];
    }
}

앞으로 전진을 벽이 있지 않으면 최소 3칸은 하도록 했다. 매번 움직일 때 마다 방향을 랜덤으로 설정했더니 너무 쉽게 혼자 꼬여서 멈춰버려서 조금이라도 덜하게 하려고 이렇게 했다. 3~5칸을 랜덤으로 전진한 뒤에 새로 방향을 설정해주는 turn()함수를 호출한다.

function turn(snake){
    const snakeHead = snake[snake.length - 1];
    let count = 0;
    while (true){
        count+=1;
        const next_dir = Math.floor(Math.random() * 10) % 4;
        const nextX = snakeHead[0]+dx[next_dir];
        const nextY = snakeHead[1]+dy[next_dir];
        if (0<=nextX && nextX<25 && 0<=nextY && nextY<25){
            if (board[nextX][nextY] === 0){
                return next_dir;
            }
        }
        if (count == 30){
            return -1;
        }
    }
}

turn함수는 동서남북 네 방향 중 전진 가능한 방향을 찾아 반환해준다. 만약 갈 수 있는 곳을 일정 횟수 시도했을 때에도 찾지 못하면 -1을 반환하면서 뱀을 처음 위치에서 다시 소환하도록 했다.

function resetSnake(snake){
    mambaCount -= 1;
    mamba.innerText = mambaCount;
    for (let i = 0; i < 9; i++){
        document.getElementById(`${snake[i][0]},${snake[i][1]}`).style.backgroundColor = "white";
        board[snake[i][0]][snake[i][1]] = 0;
    }
    return -1;
}

꼬였거나 막혀서 멈춘 뱀을 지워준다. 그리고 -1을 반환해서 addSnake()를 다시 호출할 수 있게 했다.

makeField();
button.addEventListener("click", addSnake);

마지막에는 필드 생성 함수를 호출해주고, 버튼을 클릭했을 때 뱀이 추가되도록 하는 코드를 작성했다.
나중에는 보석을 먹으면 뱀이 추가되도록 수정해야한다.

이제는 유저, 보석 추가, 타이머 추가를 하면서 관련 동작들을 추가해야한다.
그리고 오프닝과 엔딩을 앞뒤에 멋지게 넣어주면 된다.

profile
21.11.01~ 기록

0개의 댓글