본문 바로가기

javaScript

JavaScript 테트리스 만들기 - 3

728x90

2024.04.02 - [javaScript] - JavaScript 테트리스 만들기 - 1

 

JavaScript 테트리스 만들기 - 1

요즘 개발 트렌드는 javaScript를 편하게 사용하도록 도와주는 라이브러리를 활용한 개발이 아닌 순수(바닐라) javaScript를 이용한 개발이라고 어디에선가 들은 적이 있다. javaScript의 꾸준히 업데이

son33.tistory.com

2024.04.02 - [javaScript] - JavaScript 테트리스 만들기 - 2

 

JavaScript 테트리스 만들기 - 2

2024.04.02 - [javaScript] - JavaScript 테트리스 만들기 - 1 ㄴ 1에 이어서 2편으로 블록을 생성하고 시간이 지나면 블록이 아래로 내려오도록 만들어보았다. 1. 게임시작 // 게임시작 function play() { createBlock

son33.tistory.com

 

1. 블록 이동하기

// 좌, 우, 밑 그리고 스페이스바 누르기
window.addEventListener("keydown", (e) => {
    let nowBlock = document.querySelectorAll(".block");
    let shape = blockShape(nowBlock);
    let direction = { ArrowLeft: -1, ArrowRight: 1, ArrowDown: 0, ArrowUp: "ArrowUp" }[e.key];
    if (direction !== undefined && direction !== "ArrowUp") {
        if (collisionBlock(nowBlock, direction)) {
            if (direction == 0) {
                fixBlock(nowBlock);
                deleteRow(nowBlock);
                return createBlock();
            }
            return;
        } else {
            deleteBlock(nowBlock);
            // 방향에 따라 블록 새로 그리기
            let startX = parseInt(nowBlock[0].classList[0].replace("col", ""));
            let startY = parseInt(nowBlock[0].classList[1].replace("row", ""));
            if (direction == 0) {
                drawBlock(startX, startY + 1, shape);
            } else {
                drawBlock(startX + direction, startY, shape);
            }
        }
    } else if (direction === "ArrowUp") {
        rotateBlock(nowBlock);
    } else if(e.keyCode == 32){
        dropBlock(nowBlock);
    }
});

eventListener를 이용해 키보드가 눌리면 어떤 키가 눌렸는지 확인 후 블록을 이동시킬 것이다.

키보드 방향키를 이용해 <-을 누르면 블록이 왼쪽, ->를 누르면 블록이 오른쪽, 아래를 누르면 아래, 위를 누르면 블록을 회전시키고, 스페이스바를 누르면 블록이 제일 아래로 이동하도록 만들었다.

1) e.key, e.keyCode

키보드를 눌렀을 때 어떤 키가 눌렸는지를 확인하는 방법은 e.key와 e.keyCode 두 가지가 있다. e.key에서는 키보드가 눌린 키의 이름 a면 a, b면 b, <-면 ArrowLeft로 값이 반환되며 e.keyCode에서는 a면 65, b면 64, <-면 37로 값이 반환된다. e.key에서는 esc, space, enter 등의 특수키는 반환이 되지 않기 때문에 space는 keyCode에서 가져왔다.

먼저 ArrowLeft, right, down, up에 -1, 1, 0, ArrowUp값이 반환되도록 만들고, left, right, down이 눌리면 해당 방향으로 충돌여부를 확인시켰다. 충돌한다면 눌린 방향키를 확인한 뒤, 왼쪽, 오른쪽이면 바로 return 시켜 블록의 좌, 우 이동을 중지시켰다. 그 외 아래라면 지금 블록을 fixBlock()으로 보내 고정블록으로 변환하고, deleteRow()로도 보내 줄을 삭제시킬 필요가 있는지 확인한다. 거기까지 완료되면 createBlock()를 호출해 새로운 블록이 내려오도록 했다.

그리고 충돌이 일어나지 않는다면 해당 방향으로 새로운 블록을 그리게 했다.

2) 충돌감지

// 충돌 감지
function collisionBlock(nowBlock, direction) {
    const nextBlock = [];
    // 다음 위치에 있는 블록들의 위치 정보를 수집
    nowBlock.forEach(block => {
        let col = parseInt(block.classList[0].replace("col", ""));
        let row = parseInt(block.classList[1].replace("row", ""));
        if (direction == 0) {
            nextBlock.push({ col: col, row: row + 1 });
        } else if (direction == 2) {
            nextBlock.push({ col: col, row: row });
        } else {
            nextBlock.push({ col: col + direction, row: row });
        }
    });
    // 다음 위치에 다른 블록이 있는지 확인하고 충돌 감지
    const collision = nextBlock.some(pos => {
        // 다른 고정된 블록이나 바닥에 닿았을 경우
        if (pos.row > 19 || pos.col < 0 || pos.col > 9 || document.querySelector(".col" + pos.col + ".row" + pos.row + ".fixed-block") !== null) {
            return true; // 충돌 감지
        }
        return false;
    });
    return collision;
}

충돌을 감지하는 방법은 다음과 같다. 현재 블록과 방향값을 받아와 방향으로 블록을 그려본 뒤 보드판을 넘어가거나 'fixed-block'에 해당한다면 true값을 반환 아니라면 false값을 반환하게 했다.

3) fixedBlock()

// 충돌이 감지되면 현재 블록을 고정시키고 새로운 블록 생성
function fixBlock(nowBlock) {
    nowBlock.forEach(block => {
        block.classList.remove("block");
        block.classList.add("fixed-block");
    })
};

fixedBlock()은 단순히 nowBlock의 'block'을 삭제시키고 'fixed-block'을 추가시켰다.

2. 블록 회전시키기

// 블록 회전
function rotateBlock(nowBlock) {
    let startX = parseInt(nowBlock[0].classList[0].replace("col", ""));
    let startY = parseInt(nowBlock[0].classList[1].replace("row", ""));
    let shape = blockShape(nowBlock);
    const rotatedShape = [];
    // 회전된 블록 모양 계산
    const rows = shape.length;
    const cols = shape[0].length;
    for (let col = 0; col < cols; col++) {
        let newRow = [];
        for (let row = rows - 1; row >= 0; row--) {
            newRow.push(shape[row][col]);
        }
        rotatedShape.push(newRow);
    }
    // 회전된 블록 그리기 전에 이전 블록 지우기
    deleteBlock(nowBlock);
    // 회전된 블록 그리기
    let nextBlock = drawBlock(startX, startY, rotatedShape);
    if (nextBlock == false) {
        deleteBlock(document.querySelectorAll(".block"));
        if (startX < 5) {
            return rotateBlock(drawBlock(startX + 1, startY, shape));
        } else {
            return rotateBlock(drawBlock(startX - 1, startY, shape));
        }
    } else if (collisionBlock(nextBlock, 2)) {
        deleteBlock(document.querySelectorAll(".block"));
        return drawBlock(startX, startY, shape);
    }
}

블록을 회전시키기 위해 먼저 nowBlock에서 회전시킬 기준점과 nowBlock의 모양을 가져온다.

배열을 회전은 다음과 같이 구연했다. x축과 y축을 서로 바꿔 빈배열을 만들어주고, col은 0에서 길이만큼, row는 길이에서 0으로 반복하여 값을 넣어줬다. 참고로 배열은 중학교인가 고등학교 때 배우는 거니 쉬울 것이다.

기존 그려진 block은 deleteBlock()을 통해 지우고, 다음 블록을 그린 뒤 블록이 제대로 생성되었는지를 확인해 준다. 블록이 제대로 생성되지 않았다면, 회전하다가 블록이 게임판 밖에 생성되었다는 이야기이므로 게임판을 반으로 나누어 왼쪽에 있다면 시작점을 오른쪽으로 한 칸 옮긴 뒤, rotateBlock()을 다시 호출하고, 오른쪽에 있다면 왼쪽으로 한 칸 옮긴 뒤, rotateBlock()을 호출해 준다. 그럼 블록이 정상적으로 생성될 때까지 rotateBlock()을 호출할 것이다. 블록이 정상적으로 생성되었다면 생성된 블록이 충돌하는지 확인한 뒤 충돌하면 새로 그리지 않고, 충돌하지 않는다면 회전된 블록을 그려주었다.

 

728x90

'javaScript' 카테고리의 다른 글

JavaScript 테트리스 만들기 - 4  (0) 2024.04.08
JavaScript 테트리스 만들기 - 2  (0) 2024.04.02
JavaScript 테트리스 만들기 - 1  (1) 2024.04.02