코딩 강의/컨텐츠를 만들어 볼까요

테트리스 게임 개발 #2 - 블럭 모양 및 랜덤 선택 구현

아미넴 2020. 9. 12.

목차

     

    지난 강의 리뷰

    테트리스 게임 개발 #1 - HTML, 자바스크립트, CSS를 활용하여 기본 화면 구성

     

    테트리스 게임 개발 #1 - HTML, 자바스크립트, CSS를 활용하여 기본 화면 구성

    게임 개발 하면 제일 먼저 떠 오르는 종류가 보드 게임, 그 중에서도 테트리스가 아닌가 싶어요. 게다가 최근 웹 언어가 활용도가 높고 그 만큼 관심이 커지고 있기 때문에 지금부터 순수 HTML, Ja

    sangminem.tistory.com

     

    지난 포스팅에서는 테트리스 게임을 만들기 위해

    아래와 같이 기본적인 틀만 간단히 구현해 보았는데요.

     

    1. 지금부터는 main-board와 next-board에 특정 블럭을 선택하고

    2. 선택된 블럭을 그려 볼게요.

     

    블럭 모양 구성

    테트리스 게임에서는 아래와 같이 블럭의 모양을 정사각형 4개를 활용하여 7가지 형태로 만듭니다.

    위와 같은 모양을 배열 형태로 생각해 보겠습니다.

    const BLOCK_SET = [
        [
            [1,1],
            [1,1]
        ],
        [
            [0,2,0],
            [2,2,2],
            [0,0,0]
        ],
        [
            [0,3,3],
            [3,3,0],
            [0,0,0]
        ],
        [
            [4,4,0],
            [0,4,4],
            [0,0,0]
        ],
        [
            [5,0,0],
            [5,5,5],
            [0,0,0]
        ],
        [
            [0,0,6],
            [6,6,6],
            [0,0,0]
        ],
        [
            [0,0,0,0],
            [7,7,7,7],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ]

    위와 같이 초기 포지션을 고려하여 7가지 모양을 배열로 담았습니다.

    블럭을 회전했을 때의 영역까지 고려하여 행과 열의 갯수를 동일하게 맞추었구요.

    각 블럭의 모양별로 배열의 숫자 값을 다르게 하여 구분이 가능하게 하였습니다.

    0은 당연히 빈 공간을 의미합니다.

     

     

    블럭 선택 기능 구현

    그 다음 블럭 모양을 무작위로 가져와야 하므로 랜덤 함수도 하나 만들어 보겠습니다.

    function getRandomIndex(length) {
        return Math.floor(Math.random()*length);
    }

    간단하게 배열의 길이를 인자로 받아 0~(배열 길이-1)을 리턴하는 함수를 만들었습니다.

    따라서 블럭 배열의 길이를 인자로 전달하면 0~6 값을 가져 옵니다.

     

    이어서 무작위 블럭 선택 함수를 만듭니다.

    function randomNextBlockMatrix() {
        //... BLOCK_SET 배열 생략
        return BLOCK_SET[getRandomIndex(BLOCK_SET.length)];
    }

    간단하게 랜덤 함수를 이용하여 7가지 모양 중 하나를 선택하도록 하였습니다.

     

    그럼 위에서 만든 함수를 이용하여

    main-board에 표시할 블럭과 next-board에 표시할 블럭을 변수에 하나씩 담아 보겠습니다.

    //... 기존 선언 변수 생략
    let mainBlock = null;
    let nextBlock = null;
    
    function main() {
        mainBlock = createNextBlock();
        nextBlock = createNextBlock();
        //... 기존 로직 생략
    }
    
    function createNextBlock() {
        const nextBlock = {
            x: 0,
            y: 0,
            shape: randomNextBlockMatrix()
        }
    
        return nextBlock;
    }

    먼저 글로벌 변수로 mainBlock, nextBlock 변수를 선언했습니다.

    그리고 x, y 좌표 값과 블럭 모양의 배열 값을 갖는 JSON 형태 오브젝트를 리턴하는 함수를 만들어서

    main 함수에서 각 변수에 할당했습니다.

    main-board에 mainBlock을 쌓으면 다시 mainBlock에 nextBlock을 할당하는 방식으로 구현 예정입니다.

     

    화면에 그리기

    이렇게 변수에 할당만 한다고 실제 canvas에는 그려지지 않습니다.

    이제 선택된 블럭을 그리는 함수를 작성해 보겠습니다.

    function rebuild() {
        resize();
        drawBlock(mainBlock, ctxMainBoard);
        drawBlock(nextBlock, ctxNextBoard);
    }
    
    function drawBlock(block, ctx) {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    
        block.shape.forEach((row, y) => {
            row.forEach((value, x) => {
                if(value > 0) {
                    ctx.fillStyle = 'white';
                    ctx.fillRect(x + block.x, y + block.y, 1, 1);
                }
            });
        });
    }

    block과 canvas context를 인자로 받는 함수를 하나 만들었습니다.

    최초에 board를 싹 클리어 하고

    block 모양에 따른 배열 index와 블럭의 위치를 고려하여

    board에 흰색의 사각형으로 블럭을 그리는 로직입니다.

     

    그리고 rebuild 함수에 resize 함수를 포함 시키고

    각각의 블럭과 canvas context를 인자로 받아 그리도록 drawBlock 함수를 호출 하였습니다.

    그에 따라 main 함수에서 호출한 resize 함수를 rebuild 함수로 교체해 주겠습니다.

     

     

    결과 보기

    여기까지 저장을 하고 한 번 실행해 보겠습니다.

    초기 위치를 아직 설정하지 않아 맨 상단 좌측에 표시되긴 했지만

    원하는 대로 블럭이 잘 표현된 것을 볼 수 있습니다.

     

    점점 게임의 요소가 갖춰지고 있습니다.

    내 손으로 게임을 만들 수 있다니 재밌지 않나요. :)

     

    다음 포스팅에서는 main-board의 블럭을

    키보드 방향키로 움직여 보도록 하겠습니다.

     

    기대해 주세요!

     

    #다음강의

    테트리스 게임 개발 #3 - 블럭 이동 기능 구현

     

    테트리스 게임 개발 #3 - 블럭 이동 기능 구현

    목차 지난 강의 리뷰 테트리스 게임 개발 #2 - 블럭 모양 및 랜덤 선택 구현 테트리스 게임 개발 #2 - 블럭 모양 및 랜덤 선택 구현 목차 지난 강의 리뷰 테트리스 게임 개발 #1 - 소개 및 기본 화면

    sangminem.tistory.com

     

    반응형

    댓글4

    • minddi 2021.03.14 01:10

      안녕하세요, 얼마 전부터 공부를 시작한 코린이 입니다. 자바스크립트를 공부한지 얼마 되지 않았지만 테트리스를 구현해 보고자 여러 소스코드들을 보다가, 초보자가 보기 쉽게 정리를 잘 해주셔서 참고하여 공부하고 있습니다. 좋은 참고내용을 이렇게 공개해 주셔서 우선 감사의 말씀 드립니다.

      그런데 궁금한 점이 있어서 댓글 남깁니다.
      drawBlock함수에서 ctx.fillRect(x + block.x, y + block.y, 1, 1);
      이 부분이 이해가 잘 가지 않습니다.
      1. x 와 y가 나타내는 지점이 어디인지 잘 모르겠습니다.
      2. block.x와 block.y는 createBlock함수에서 각각 0으로 지정해 둔 거 아닌가요?
      왜 굳이 x + block.x 라고 쓰셨나요??

      답변 달아주시기 전까지 스스로 답을 찾을 수 있게 노력 하겠습니다만, 답변 달아주시면 감사하겠습니다. :)
      답글

      • 아미넴 2021.03.14 01:20 신고

        안녕하세요 ㅎㅎ 코딩 공부하신다니 반갑네요.

        이 다음 포스팅을 보시면 바로 알 수 있으실 텐데요~ 블럭을 이동하게 되면 block.x, block.y 값이 변하게 됩니다.

        최초 한 번만 이용하고 끝인 함수가 아니고 지속적으로 사용해야 하는 함수이므로 일반적인 경우를 생각하고 작성하는 것이 좋습니다.

      • minddi 2021.03.15 15:17

        답변 감사드립니다!
        x 와 y가 나타내는 값은 하나씩 콘솔창에 나타내면서 보니까 무엇을 나타내는건지 알겠더라구요!

        x는 하나의 블럭을 구성하는 각각의 네모들의 x좌표로 이해했는데, 그럼 block.x의 값은 한개가 아닌게 맞나요??

      • 아미넴 2021.03.15 18:51 신고

        오네 x, y 값에 대해서는 잘 이해하셨네요.

        다만 block.x와 block.y는 하나의 값을 가집니다. 블럭을 구성하는 모든 x, y값은 동일한 값만큼 이동할 것이므로 여러 개 둘 필요가 없겠죠 ㅎㅎ

    💲 추천 글