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

테트리스 게임 개발 #9 - 콤보 기능 및 라인 한 줄 씩 추가

아미넴 2020. 10. 1.
반응형

목차

     

    지난 강의 리뷰

    테트리스 게임 개발 #8 - 보드 및 블럭 스타일 추가

     

    테트리스 게임 개발 #8 - 보드 및 블럭 스타일 추가

    목차 지난 강의 리뷰 테트리스 게임 개발 #7 - 최고 점수 표시, 블럭 색깔 추가, 배경음악 및 효과음 적용 테트리스 게임 개발 #7 - 최고 점수 표시, 블럭 색깔 추가, 배경음악 및 효과음 적용 목차

    sangminem.tistory.com

     

    이번 시간에는 한층 더 고급스러워진 게임에 더욱 난이도 높은 기능을 추가해 보도록 해볼게요.

     

    1. 먼저 콤보 기능을 만들어 볼 거구요.

    2. 특정 레벨 이상에서 일정 시간이 지나면 밑에서 한 줄씩 올라오는 로직을 구현해 보겠습니다.

     

    별 거 아닌 거 같아도 생각보다 고려할 게 많습니다.

    정신 바짝 차리고 따라 오세요.

     

    콤보 기능 추가

    콤보 기능을 위해 콤보 횟수를 계산하는 방법을 생각해 볼게요.

    //... 생략
    
    let comboCount = 0;

    global.js 파일에 전역 변수 comboCount 하나만 있으면 구현이 가능해 보입니다.

     

    연속으로 2회 이상 라인을 제거할 경우 콤보 기능이 작동하도록 로직을 수정하면 되겠죠.

    function nextStep() {
        //... 생략
    
        if(filledLines.length === 0) {
            comboCount = 0;
            //...생략
        }
    }
    
    function repeatMotion(timeStamp) {
        //... 생략
    
        if(filledLines.length > 0) {
            //... 생략
            if(timeStamp - timeForRemovingLines > 100) {
                comboCount++;
                globalAddScore += 100*filledLines.length*currentLevel*comboCount;
                //... 생략
            }
        }
    
        //... 생략
    }

    일단 라인이 제거될 경우에 콤보 카운트 변수를 1씩 증가하도록 하였고

    nextStep 함수에서 제거된 라인이 0이면 콤보 카운트 변수를 0으로 초기화 하였습니다.

    그리고 라인 제거 점수 계산 시 콤보 카운트 횟수 만큼 곱하여 획득 점수에 영향을 주었습니다.

     

    콤보를 몇 번 했는 지도 화면에 표현해 주면 더욱 좋을 것 같습니다.

    draw.js 파일에 함수를 하나 만들어 볼게요.

    function drawCombo(ctx, comboCount, colorSet) {
        if(comboCount > 1) {
            let adjustTextPosition = 0;
            if(String(comboCount-1).length >= 2) {
                adjustTextPosition = -0.2;
            }
            if(comboCount%2 === 0) {
                ctx.globalAlpha = 0.5;
                ctx.fillStyle = colorSet[comboCount%7];
                ctx.fillRect(6, 0.2, 4, 1.6);
                ctx.globalAlpha = 1.0;
                ctx.font = '1px NeoDungGeunMo';
                ctx.fillStyle = '#ffffff';
                ctx.fillText('콤보 +'+(comboCount-1), 6.2+adjustTextPosition, 1.3);
            } else {
                ctx.globalAlpha = 0.5;
                ctx.fillStyle = colorSet[comboCount%7];
                ctx.fillRect(0, 0.2, 4, 1.6);
                ctx.globalAlpha = 1.0;
                ctx.font = '1px NeoDungGeunMo';
                ctx.fillStyle = '#ffffff';
                ctx.fillText('콤보 +'+(comboCount-1), 0.2+adjustTextPosition, 1.3);
            }
        }
        ctx.globalAlpha = 1.0;
    }

    콤보 횟수가 1회 이상(comboCount 변수가 2 이상)일 때 상단 좌우측에 번갈아 가며 한 번씩 표현 되도록 하였고

    opacity 값은 0.5 정도로 주었습니다.

    텍스트 박스 색깔은 블럭 색 7가지 지정한 것을 그대로 사용하였는데 따로 만들어도 상관은 없습니다.

    콤보 횟수가 2자리 수가 넘어갈 경우를 대비하여 포지션 조정하는 변수를 하나 선언하였습니다.

    함수 마지막에는 다른 drawing 작업에 영향을 끼치지 않도록 opacity 값을 1.0으로 원상복귀 시킵니다.

     

    main.js 파일에 만든 drawCombo 함수를 호출하도록 합니다.

    function rebuild() {
        //... 생략
        drawCombo(ctxMainBoard, comboCount, COLOR_SET);
    }

    최상단 레이어에 그려지도록 하기 위해 rebuild 함수 맨 마지막에서 호출하였습니다.

     

     

     

     

    중간 확인

    그럼 한 번 실행해 볼까요!

    상당히 잘 표현되고 점수도 콤보 횟수에 따라 계산이 됩니다.

     

    라인 한 줄 씩 추가

    그럼 밑에서 한 줄 씩 올라오는 로직도 생각해 볼게요.

    먼저 필요 전역 변수를 선언하겠습니다.

    //... 생략
    
    const levelToStartForMakingOneLine = 5;
    let timeForMakingOneLine = 0;

    global.js 파일에 시작할 레벨을 설정하고,

    애니메이션 함수에서 시간을 계산하기 위한 변수도 하나 선언해 주었습니다.

     

    그리고 main.js 파일에 함수를 하나 구현해 보도록 하겠습니다.

    function makeOneLine() {
        let cloneBoard = JSON.parse(JSON.stringify(matrixMainBoard));
    
        const randomIndex = getRandomIndex(COLS_MAIN_BOARD);
        const opacitySet = ['1.0','0.95','0.9','0.85'];
        let tempBoard = [];
        let tempOptions = [];
        for(let x=0; x < COLS_MAIN_BOARD;x++){
            if(x === randomIndex) {
                tempBoard.push(0);
                tempOptions.push({opacity: '1.0'});
            } else {
                tempBoard.push(8);
                tempOptions.push({opacity: opacitySet[getRandomIndex(4)]});
            }
        }
    
        cloneBoard.board.shift();
        cloneBoard.board.push(tempBoard);
        cloneBoard.options.shift();
        cloneBoard.options.push(tempOptions);
    
    
        let cloneBlock = JSON.parse(JSON.stringify(mainBlock));
        if(validMove(cloneBlock, cloneBoard, 0, 0)){
            matrixMainBoard = cloneBoard;
        }
    }

    한 라인을 바닥에 깔고 기존 블럭을 위로 한 줄 씩 올리는 로직을 구현했습니다.

    동작에 대한 검증 없이 실제 main-board에 바로 drawing 하면 안 되므로

    우선 main-board에 대응하는 matrix를 복제를 하였습니다.

    먼저 바닥에 깔 라인 한 줄을 랜덤 함수를 이용하여 임시로 만들었습니다.

    색깔은 회색(8)으로 설정했고, opacity 옵션도 랜덤으로 네 가지 중 한 가지를 선택하는 로직을 만들었습니다.

    그런 다음 복제된 main-board의 맨 윗 라인을 날리고 미리 만든 한 줄을 맨 아래에 삽입했습니다.

     

    그런 다음 검증을 위해 메인 블럭도 복제를 했습니다.

    복제한 블럭을 한 줄 삽입한 복제된 보드에서 유효한 위치인지 검증을 하고

    최종적으로 게임이 이루어지고 있는 main-board에 대입을 해 주었습니다.

     

    만든 함수를 repeatMotion 함수에서 실제 호출을 해 보겠습니다.

    function repeatMotion(timeStamp) {
        //... 생략
    
        if(currentLevel >= levelToStartForMakingOneLine) {
            if(timeForMakingOneLine === 0) {
                timeForMakingOneLine = timeStamp;
            }
    
            if(timeStamp - timeForMakingOneLine > 10000/(currentLevel-levelToStartForMakingOneLine+1)*2) {
                makeOneLine(); // 추가
                timeForMakingOneLine = timeStamp;
            }
        }
        
        //... 생략
    }

    일정 레벨 이상일 경우에만 적용되도록 하였고

    레벨에 따라 속도를 높이는 방식으로 조건을 만들어 만든 함수를 호출하였습니다.

    속도는 원하는 대로 조절하셔도 무방합니다.

     

     

     

     

    결과 확인

    저장하고 다시 실행을 한 번 해 보겠습니다.

    밑에서 블럭이 계속 올라와 더욱 박진감 넘치는 게임이 되었습니다.

     

    그런데 모바일 기기가 대세인 시대에 컴퓨터로만 게임을 할 수 있으면 만든 보람이 반감되겠죠.

    다음 시간에는

    모바일로도 플레이 가능하도록 조작 버튼을 만들어 보도록 하겠습니다.

     

    앞으로도 계속 기대해 주세요. :)

     

    #다음강의

    테트리스 게임 개발 #10 - 모바일 플레이 기능 구현

     

    테트리스 게임 개발 #10 - 모바일 플레이 기능 구현

    목차 지난 강의 리뷰 테트리스 게임 개발 #9 - 콤보 기능 및 라인 한 줄 씩 추가 테트리스 게임 개발 #9 - 콤보 기능 및 라인 한 줄 씩 추가 목차 지난 강의 리뷰 테트리스 게임 개발 #8 - 보드 및 블

    sangminem.tistory.com

     

    반응형

    댓글

    💲 추천 글