본문 바로가기
JavaScript

[JavaScript] 간단한 테트리스 게임 만들기 (2) - 레벨업 하기

by teamnova 2024. 9. 4.
728x90

안녕하세요 오늘은 지난번에 만들었던 테트리스 게임에 

레벨업 기능을 추가시켜보도록 하겠습니다. 

기존 게임에서는 1초 간격으로 블럭이 하단으로 떨어지도록 구현하였습니다. 

전체 코드는 하단에서 확인하실 수 있습니다 

 

오늘은 여기에 레벨업 기능을 추가하여 1분마다 블럭의 하강 속도가 기존 속도대비 20%씩 빨라지도록 구현해보겠습니다.

간단한 테트리스 게임 만들기 1편은 아래 링크에서 확인하실 수 있습니다.  

 

[JavaScript] 간단한 테트리스 게임 만들기

오늘은 자바 스크립트로 간단한 테트리스 게임을 만들어보도록 하겠습니다. 먼저 HTML  코드입니다 (자바 스크립트 전체 코드는 게시글 하단에서 확인하실 수 있습니다)  테트리스 도형이 쌓

stickode.tistory.com

 

 

 

자바스크립트 코드입니다. 

변경된 부분은 아래와 같습니다. 

// 1분마다 레벨을 증가시키고, 속도를 올리는 타이머
setInterval(() => {
    increaseLevel();
}, 60000);


let level = 0;
let linesCleared = 0;

// 레벨 증가 및 속도 조절 함수
function increaseLevel() {
    level += 1;
    dropInterval *= 0.8;  // 속도 증가 비율을 20%로 조정
    updateLevelAndSpeed();  // 레벨과 속도 UI 업데이트
}

// 레벨과 속도 UI 업데이트 함수
function updateLevelAndSpeed() {
    document.getElementById('level').textContent = `Level: ${level}`;
    document.getElementById('speed').textContent = `Speed: ${Math.round(dropInterval)}ms`;
}

 

기존 속도에서 20% 증가되도록 dropInterval 변수에 0.8 을 곱해줍니다. 

html 파일의 ui 요소를 1분마다 변경해줍니다. 

(현재 레벨이 0부터 시작하도록 설정되어 있습니다. )

 

 

 

현재 레벨과 블럭 속도를 표시하는 div 가 추가된 html 코드입니다 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tetris Game</title>
    <style>
        canvas {
            background-color: #000;
            display: block;
            margin: 0 auto;
            color: rgb(0, 0, 0);  /* 글씨 색상을 흰색으로 명확히 설정 */
            border: 2px solid;
        }
        #info {
            text-align: center;
            color: rgb(0, 0, 0); 
            font-family: Arial, sans-serif;
            margin-top: 10px;
        }
        #level, #speed {
            font-size: 18px;
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <canvas id="tetris" width="300" height="600"></canvas>
    <div id="info">
        <div id="level">Level: 0</div>
        <div id="speed">Speed: 1000ms</div>
    </div>
    <script src="tetris1.js"></script>
</body>
</html>

 

레벨, 속도를 표시하는 info 블럭을 컨버스 아래에 추가해줍니다 

 

 

전체 코드는 아래와 같습니다 

 

tetris1.js 

const canvas = document.getElementById('tetris');
const context = canvas.getContext('2d');

const grid = 20;  // 테트리스 그리드 크기
const cols = canvas.width / grid;
const rows = canvas.height / grid;

let board = Array.from({ length: rows }, () => Array(cols).fill(0));

const colors = [
    null,
    'cyan',
    'blue',
    'orange',
    'yellow',
    'green',
    'purple',
    'red'
];

const tetrominoes = [
    [
        [1, 1, 1, 1],  // I
    ],
    [
        [0, 2, 0],
        [2, 2, 2],     // T
    ],
    [
        [3, 3],
        [3, 3],        // O
    ],
    [
        [0, 4, 4],
        [4, 4, 0],     // S
    ],
    [
        [5, 5, 0],
        [0, 5, 5],     // Z
    ],
    [
        [6, 0, 0],
        [6, 6, 6],     // J
    ],
    [
        [0, 0, 7],
        [7, 7, 7],     // L
    ]
];

function createPiece(type) {
    return tetrominoes[type];
}

function drawMatrix(matrix, offset) {
    matrix.forEach((row, y) => {
        row.forEach((value, x) => {
            if (value !== 0) {
                context.fillStyle = colors[value];
                context.fillRect((x + offset.x) * grid, (y + offset.y) * grid, grid, grid);
            }
        });
    });
}

function collide(board, player) {
    const [m, o] = [player.matrix, player.pos];
    for (let y = 0; y < m.length; y++) {
        for (let x = 0; x < m[y].length; x++) {
            if (m[y][x] !== 0 &&
               (board[y + o.y] &&
                board[y + o.y][x + o.x]) !== 0) {
                return true;
            }
        }
    }
    return false;
}



function merge(board, player) {
    player.matrix.forEach((row, y) => {
        row.forEach((value, x) => {
            if (value !== 0) {
                board[y + player.pos.y][x + player.pos.x] = value;
            }
        });
    });
    clearLines();
}


function clearLines() {
    outer: for (let y = board.length - 1; y >= 0; y--) {
        for (let x = 0; x < board[y].length; x++) {
            if (board[y][x] === 0) {
                continue outer;
            }
        }
        const row = board.splice(y, 1)[0].fill(0);
        board.unshift(row);
        linesCleared += 1;

     
    }
}



let dropCounter = 0;
let dropInterval = 1000;
let lastTime = 0;

function update(time = 0) {
    const deltaTime = time - lastTime;
    lastTime = time;

    dropCounter += deltaTime;
    if (dropCounter > dropInterval) {
        playerDrop();
    }

    draw();
    requestAnimationFrame(update);
}

function playerDrop() {
    player.pos.y++;
    if (collide(board, player)) {
        player.pos.y--;
        merge(board, player);
        playerReset();
    }
    dropCounter = 0;
}

function playerMove(dir) {
    player.pos.x += dir;
    if (collide(board, player)) {
        player.pos.x -= dir;
    }
}

function playerReset() {
    player.matrix = createPiece(Math.floor(Math.random() * tetrominoes.length));
    player.pos.y = 0;
    player.pos.x = Math.floor((cols - player.matrix[0].length) / 2);

    if (collide(board, player)) {
        board.forEach(row => row.fill(0));
    }
}

function draw() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    drawMatrix(board, { x: 0, y: 0 });
    drawMatrix(player.matrix, player.pos);
}

function rotate(matrix, dir) {
    for (let y = 0; y < matrix.length; y++) {
        for (let x = 0; x < y; x++) {
            [matrix[x][y], matrix[y][x]] = [matrix[y][x], matrix[x][y]];
        }
    }
    if (dir > 0) {
        matrix.forEach(row => row.reverse());
    } else {
        matrix.reverse();
    }
    return matrix;
}

const player = {
    pos: { x: 0, y: 0 },
    matrix: createPiece(Math.floor(Math.random() * tetrominoes.length))
};

document.addEventListener('keydown', event => {
    if (event.keyCode === 37) {
        playerMove(-1);
    } else if (event.keyCode === 39) {
        playerMove(1);
    } else if (event.keyCode === 40) {
        playerDrop();
    } else if (event.keyCode === 81) {
        player.matrix = rotate(player.matrix, -1);
    } else if (event.keyCode === 87) {
        player.matrix = rotate(player.matrix, 1);
    }
});

update();

// 1분마다 레벨을 증가시키고, 속도를 올리는 타이머
setInterval(() => {
    increaseLevel();
}, 60000);


let level = 0;
let linesCleared = 0;

// 레벨 증가 및 속도 조절 함수
function increaseLevel() {
    level += 1;
    dropInterval *= 0.8;  // 속도 증가 비율을 20%로 조정
    updateLevelAndSpeed();  // 레벨과 속도 UI 업데이트
}

// 레벨과 속도 UI 업데이트 함수
function updateLevelAndSpeed() {
    document.getElementById('level').textContent = `Level: ${level}`;
    document.getElementById('speed').textContent = `Speed: ${Math.round(dropInterval)}ms`;
}


// 게임 시작 시 UI 초기화
updateLevelAndSpeed();

 

 

 

tetris.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tetris Game</title>
    <style>
        canvas {
            background-color: #000;
            display: block;
            margin: 0 auto;
            color: rgb(0, 0, 0);  /* 글씨 색상을 흰색으로 명확히 설정 */
            border: 2px solid;
        }
        #info {
            text-align: center;
            color: rgb(0, 0, 0); 
            font-family: Arial, sans-serif;
            margin-top: 10px;
        }
        #level, #speed {
            font-size: 18px;
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <canvas id="tetris" width="300" height="600"></canvas>
    <div id="info">
        <div id="level">Level: 0</div>
        <div id="speed">Speed: 1000ms</div>
    </div>
    <script src="tetris1.js"></script>
</body>
</html>

 

 

 

시연 영상입니다