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

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

아미넴 2020. 9. 24.
반응형

목차

     

    지난 강의 리뷰

    테트리스 게임 개발 #6 - 시작, 종료, 일시 정지 및 레벨, 라인, 점수 계산 기능 구현

     

    테트리스 게임 개발 #6 - 시작, 종료, 일시 정지 및 레벨, 라인, 점수 계산 기능 구현

    목차 지난 강의 리뷰 테트리스 게임 개발 #5 - 하드 드랍 및 라인 제거 기능 구현 테트리스 게임 개발 #5 - 하드 드랍 및 라인 제거 기능 구현 목차 지난 강의 리뷰 테트리스 게임 개발 #4 - 블럭 쌓

    sangminem.tistory.com

     

    점점 게임의 완성도가 높아지고 있습니다.

    기세를 몰아서 더욱 높여 보겠습니다.

     

    1. 최고 점수 표시

    2. 블럭 색깔 추가

    3. 배경음, 효과음 적용

     

    위 3가지 사항을 이번에도 거침없이 적용할 예정이에요.

     

    소스 코드 재정비

    잠시 다시 한 번 코드 관리하기 좋도록 파일 정비를 하고 가겠습니다.

    처음부터 제대로 잡고 갔으면 더 좋았겠지만 좀 미흡했던 점 인정합니다..

    보시는대로 css / js / resources 폴더를 새로 만들어서 파일 종류별로 분류를 했습니다.

    resources에는 폰트 및 배경음, 효과음 파일들을 넣었습니다.

    mp3 파일은 맨 아래에서 첨부 파일로 공유할테니 학습 목적으로만 이용해 주세요. :)

     

    당연한 거지만 파일 import한 부분도 수정해 주겠습니다.

    <!DOCTYPE html>
    <html>
        <head>
            <!-- 생략 -->
            <link href="./css/common.css" rel="stylesheet"/>
        </head>
        <body>
            <!-- 생략 -->
            <script src='./js/common.js'></script>
            <script src='./js/matrix.js'></script>
            <script src='./js/move.js'></script>
            <script src='./js/draw.js'></script>
            <script src='./js/global.js'></script>
            <script src='./js/main.js'></script>
        </body>
    </html>

    먼저 play.html 부분을 수정했구요.

    @font-face {
        font-family: 'NeoDungGeunMo';
        src: url('../resources/neodgm.woff') format('woff');
        font-weight: normal;
        font-style: normal;
    }
    
    /* 나머지 부분 생략 */

    common.css 파일에도 폰트를 현재 위치에 맞게 상대 경로로 바꾸어 주었습니다.

     

     

    최고 점수 기록

    지금부터 최고 점수를 기록해 보는 기능을 만들어 볼게요.

    <!DOCTYPE html>
    <html>
        <!-- 생략 -->
        <body>
            <div class="wrap">
                <!-- 생략 -->
                <div id="side-contents" class="side-contents">
                <!-- 생략 -->
                    <p>
                        <span class="high-score-title">#최고점수</span><br>
                        <span id="high-score">0</span>
                    </p>
                    <!-- 생략 -->
                </div>
            </div>
            <!-- 생략 -->
        </body>
    </html>

    side-contents 하위에 최고 점수 기록을 위한 자리를 잡아 두었습니다.

    /* 기존 스타일 생략 */
    
    .high-score-title {
        color: #ffa3a3;
    }

    타이틀에 색깔을 입히기 위해 간단히 css도 작성하였습니다.

     

    global.js 파일에 점수를 표시하기 위해 엘리먼트를 담을 전역 변수 선언도 해 놓겠습니다.

    //... 기존 선언 변수 생략
    
    let highScoreElem = document.querySelector('#high-score');

     

    그리고 점수를 로컬스토리지에 저장하여 같은 브라우저 내에서는 기록이 계속 남아 있도록 하겠습니다.

    디비에 기록을 할 수도 있지만 배보다 배꼽이 커지는 작업이므로 여기서는 생략하겠습니다.

    function main() {
        //... 생략
        highScoreElem.textContent = localStorage.getItem('high-score')||0;
    }
    
    function quit() {
        //... 생략
        
        let highScore = Number(highScoreElem.textContent);
        if(totalScore > highScore) {
            localStorage.setItem('high-score', totalScore);
            highScoreElem.textContent = totalScore;
            ctxMainBoard.fillText('기록 갱신', 2.8, 4.2);
        } else {
            ctxMainBoard.fillText('게임 오버', 2.8, 4.2);
        }
        gameStatus = 'Q';
    }

    먼저 main 함수에서 high-score 라는 키로 저장된 값이 있는지 보고 없으면 0을 high-score 엘리먼트에 대입합니다.

     

    quit 함수에서는 게임이 종료되는 시점에 기존 최고 점수와 비교하여 더 높으면 새로 저장을 합니다.

    그리고 '게임 오버' 대신 '기록 갱신' 이라는 글자를 보여주도록 했습니다.

     

    블럭에 색깔 적용

    다음으로 블럭에 색깔을 넣어 보겠습니다.

    넣을 색깔은 적당히 지정을 합니다.

    각자 더욱 예쁜 색으로 능력껏 꾸며주세요.

    //... 기존 선언 변수 생략
    
    const COLOR_SET = [
        '#1726f3',
        '#df2736',
        '#38a73b',
        '#fc902c',
        '#6f4af7',
        '#ffd151',
        '#1c2491',
        '#9c9c9c'
    ];

    색깔은 블럭 및 main-board에서도 사용을 하고자 global.js 파일에 전역 변수로 선언을 해 주었습니다.

     

    그리고 draw.js 파일을 수정해 보겠습니다.

    function drawBlock(block, ctx, colorSet) {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        block.shape.forEach((row, y) => {
            row.forEach((value, x) => {
                if(value > 0) {
                    ctx.fillStyle = colorSet[value-1]; // 변경된 부분
                    ctx.fillRect(x + block.x, y + block.y, 1, 1);
                }
            });
        });
    }
    
    function drawBoard(matrix, ctx, colorSet) {
        matrix.board.forEach((row, y) => {
            row.forEach((value, x) => {
                if(value > 0) {
                    ctx.fillStyle = colorSet[matrix[y][x]-1]; // 변경된 부분
                    ctx.fillRect(x, y, 1, 1);
                }
            });
        });
    }

    단순히 컬러셋을 인자로 받아서 각 블럭이 갖고 있는 숫자 값을 인덱스로 활용을 했습니다.

     

     

    배경음악, 효과음 적용

    마지막으로 배경음과 효과음을 넣어 보겠습니다.

     

    일단 play.html 파일에 audio 태그를 넣어서 사운드 재생을 할 건데요.

    <!DOCTYPE html>
    <html>
        <!-- 생략 -->
        <body>
            <div class="wrap">
                <!-- 생략 -->
                <div id="side-contents" class="side-contents">
                    <!-- 생략 -->
                    <p>
                        <button id="toggle-sound-button" onclick="toggleSound()" class="toggle-sound-button">소리 끄기</button>
                    </p>
                </div>
            </div>
            <audio loop id='bgm' src='./resources/bgm.mp3'></audio>
            <audio id='sound'></audio>
            <!-- 생략 -->
        </body>
    </html>

    맨 처음 언급했던 mp3 파일들을 활용하여 bgm 부분은 loop 속성을 주어 반복 재생하도록 하였습니다.

    그리고 효과음을 위한 audio 태그도 하나 더 작성해 두었습니다.

    그리고 소리를 켜고 끄는 버튼도 하나 만들었습니다.

     

    common.css 파일에서 버튼 스타일도 적당히 지정해 보겠습니다.

    /* 기존 스타일 생략 */
    
    .toggle-sound-button {
        background-color: #e7c03e;
        border: 2px solid #c79409;
        color: #7e5600;
        text-align: center;
    }

     

    global.js 파일에 필요한 전역 변수 선언도 하겠습니다.

    //... 기존 선언 변수 생략
    
    const toggleSoundButton = document.querySelector('#toggle-sound-button');
    const soundElem = document.querySelector('#sound');
    const bgmElem = document.querySelector('#bgm');
    let allowSound = true;
    
    /* 사파리 오디오 지연 문제 해결 */
    const AudioContext = window.AudioContext || window.webkitAudioContext;
    const audioCtx = new AudioContext();

    먼저 버튼과 각 audio 엘리먼트들을 가져 왔구요.

    소리를 끄고 켤 수 있는 기능을 만들기 위해 boolean 변수도 하나 만들었습니다.

    맥 사파리에서 소리 재생이 느리면 아래 두 줄을 추가해 보세요.

    일단 해결은 되는 걸로 보입니다만 이유는 모르겠습니다.

     

    main.js 파일도 수정을 해 보면,

    function start() {
        bgmElem.play();
        //... 생략
    }
    
    function quit() {
        bgmElem.pause();
        bgmElem.currentTime = 0;
        //... 생략
    }

    start 함수에서 bgm을 재생하고 quit 함수에서 중단하고 타임을 맨 앞으로 돌리면 됩니다.

     

    이어서 효과음 부분을 생각해 볼게요.

    function playSound(type) {
        if(allowSound) {
            switch(type) {
                case 'drop':
                    soundElem.src = './resources/drop.mp3';
                    break;
                case 'remove':
                    soundElem.src = './resources/remove.mp3';
                    break;
            }
            if(soundElem.paused) { 
                soundElem.play();
            } else { 
                soundElem.pause(); 
                soundElem.currentTime = 0;
                soundElem.play();
            } 
        }
    }
    
    function nextStep() {
        //... 생략
        
        if(filledLines.length === 0) {
            playSound('drop');
            //... 생략
        }
    }
    
    function repeatMotion(timeStamp) {
        //... 생략
    
        if(filledLines.length > 0) {
            //... 생략
            if(timeStamp - timeForRemovingLines > 100) {
                playSound('remove');
                //... 생략
            }
        }
        //... 생략
    }

    먼저 효과음을 간단히 호출하기 위한 playSound 함수를 하나 만들었습니다.

    타입에 따라 소스 사운드 파일을 교체해 주는 방식으로 구현을 했습니다.

    그 함수를 이용하여 nextStep에서 라인 제거 수가 0일 때는 drop 효과음을

    repeatMotion 함수에서 라인 제거 수가 0보다 클 때는 remove 효과음을 재생하도록 했습니다.

     

    그리고 소리를 켜고 끌 수 있는 토글 함수도 만들어 볼게요.

    function toggleSound() {
        if(bgmElem.paused) {
            allowSound = true;
            bgmElem.play();
            toggleSoundButton.textContent = '소리 끄기';
        } else {
            allowSound = false;
            bgmElem.pause();
            bgmElem.currentTime = 0;
            toggleSoundButton.textContent = '소리 켜기';
        }
    }

    배경 음악의 상태를 체크하여 켜고 끄도록 했고 그와 함께 allowSound 전역 변수를 통해 효과음도 제어 가능하도록 만들었습니다.

     

     

    결과 확인

    이제 저장하고 실행해 보겠습니다.

    최고 점수 표시도 잘 되고 블럭의 색깔도 잘 입혀졌습니다.

    이미지로는 알 수 없지만 소리도 잘 나네요. :)

     

    다음 시간에도 계속 게임 요소를 하나하나 추가해 나갈 거예요. 

     

    블럭 모양을 좀 더 다듬고

    바닥에서 올라오는 블럭도 구현해 보도록 할게요.

    그리고 1자 모양 블럭의 색깔이 바탕색과 비슷해서 잘 안 보이는데 보드에도 밝은 무늬를 적용해 보겠습니다.

    1자 모양 색깔을 바꿔도 되는거 아니냐 하시는 분이 계실텐데 제 마음 입니다 :)

     

    그럼 다음 시간에 다시 만나요!

     

    #첨부 사운드 파일 다운 받아서 사용하세요~

    bgm.mp3
    0.38MB
    drop.mp3
    0.00MB
    remove.mp3
    0.00MB

     

     

    #다음강의

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

     

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

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

    sangminem.tistory.com

     

    반응형

    댓글

    💲 추천 글