PauloRB.dev

Desenvolvedor de Software

Tutorial de Desenvolvimento: Criando um Jogo de Tetris | PauloRB.dev Tutorial de Desenvolvimento: Criando um Jogo de Tetris – PauloRB.dev
Tutorial de Desenvolvimento: Criando um Jogo de Tetris

Tutorial de Desenvolvimento: Criando um Jogo de Tetris

E vamos a mais um tutorial de outro joguinho clássico só que dessa vez vamos recriar o Tetris.

Link do repositório: https://github.com/paulodm145/tetris

Estrutura do Projeto

/projeto-tetris

├── index.html
├── styles.css
└── script.js

1. index.html

Este arquivo contém a estrutura básica da página do jogo.

<!DOCTYPE html>
<html lang="pt">
<head>
    <meta charset="UTF-8">
    <title>Tetris</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div id="tetris-container">
        <div id="score">Pontuação: <span>0</span></div>
        <div id="tetris"></div>
        <div class="buttons">
            <button id="restart">Reiniciar</button>
            <button id="pause">Pausar</button>
            <button id="reset-score">Zerar Pontuação</button>
        </div>
    </div>
    <script src="script.js"></script>
</body>
</html>

  • Cabeçalho: Contém as configurações básicas e a inclusão do arquivo CSS.
  • Corpo: Inclui o contêiner principal do jogo, o tabuleiro (#tetris), a exibição da pontuação e os botões de controle.

2. styles.css

Este arquivo contém os estilos do jogo.

body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background-color: #e0e0e0;
    font-family: Arial, sans-serif;
    margin: 0;
}

#tetris-container {
    display: flex;
    flex-direction: column;
    align-items: center;
}

#tetris {
    width: 300px;
    height: 600px;
    border: 2px solid #333;
    background-color: #fff;
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    grid-template-rows: repeat(20, 1fr);
    gap: 1px;
    margin-bottom: 20px;
}

#tetris div {
    background-color: #f0f0f0;
    box-sizing: border-box;
}

#score {
    font-size: 1.5em;
    color: #333;
    margin-bottom: 10px;
}

#score span {
    font-weight: bold;
}

.buttons {
    display: flex;
    gap: 10px;
}

button {
    padding: 10px 20px;
    font-size: 1em;
    color: #fff;
    background-color: #007bff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s;
}

button:hover {
    background-color: #0056b3;
}

  • Estilos Básicos: Define o layout da página e do contêiner do jogo.
  • Tabuleiro: Configura o tamanho e o estilo do tabuleiro de Tetris.
  • Botões: Estiliza os botões de controle com cores e transições.

3. script.js

Este arquivo contém a lógica do jogo de Tetris.

document.addEventListener('DOMContentLoaded', () => {
    const grid = document.querySelector('#tetris');
    const width = 10;
    let timerId;
    let score = 0;
    const colors = ['orange', 'red', 'purple', 'green', 'blue'];

    // Criar a grade e preencher com divs
    function createBoard() {
        for (let i = 0; i < 200; i++) { // 200 divs para o tabuleiro
            let square = document.createElement('div');
            grid.appendChild(square);
        }
        for (let i = 0; i < 10; i++) { // 10 divs para a linha de base
            let square = document.createElement('div');
            square.classList.add('taken');
            grid.appendChild(square);
        }
    }
    createBoard();

    let squares = Array.from(grid.querySelectorAll('div'));
    const scoreDisplay = document.querySelector('#score span');
    let nextRandom = 0; // inicialização correta de nextRandom

    // Os Tetrominos e suas rotações
    const lTetromino = [
        [1, width+1, width*2+1, 2],
        [width, width+1, width+2, width*2+2],
        [1, width+1, width*2+1, width*2],
        [width, width*2, width*2+1, width*2+2]
    ];

    const zTetromino = [
        [0, width, width+1, width*2+1],
        [width+1, width+2, width*2, width*2+1],
        [0, width, width+1, width*2+1],
        [width+1, width+2, width*2, width*2+1]
    ];

    const tTetromino = [
        [1, width, width+1, width+2],
        [1, width+1, width+2, width*2+1],
        [width, width+1, width+2, width*2+1],
        [1, width, width+1, width*2+1]
    ];

    const oTetromino = [
        [0, 1, width, width+1],
        [0, 1, width, width+1],
        [0, 1, width, width+1],
        [0, 1, width, width+1]
    ];

    const iTetromino = [
        [1, width+1, width*2+1, width*3+1],
        [width, width+1, width+2, width+3],
        [1, width+1, width*2+1, width*3+1],
        [width, width+1, width+2, width+3]
    ];

    const theTetrominos = [lTetromino, zTetromino, tTetromino, oTetromino, iTetromino];

    let currentPosition = 4;
    let currentRotation = 0;
    let random = Math.floor(Math.random() * theTetrominos.length);
    let current = theTetrominos[random][currentRotation];

    // Desenhar o Tetromino
    function draw() {
        current.forEach(index => {
            squares[currentPosition + index].style.backgroundColor = colors[random];
        });
    }

    // Desfazer o desenho do Tetromino
    function undraw() {
        current.forEach(index => {
            squares[currentPosition + index].style.backgroundColor = '';
        });
    }

    // Fazer o Tetromino cair a cada segundo
    timerId = setInterval(moveDown, 1000);

    // Mover Tetromino para baixo
    function moveDown() {
        undraw();
        currentPosition += width;
        draw();
        freeze();
    }

    // Congelar quando o Tetromino atinge o fundo da grade
    function freeze() {
        if (current.some(index => squares[currentPosition + index + width].classList.contains('taken'))) {
            current.forEach(index => squares[currentPosition + index].classList.add('taken'));
            random = nextRandom;
            nextRandom = Math.floor(Math.random() * theTetrominos.length);
            current = theTetrominos[random][currentRotation];
            currentPosition = 4;
            draw();
            addScore();
            gameOver();
        }
    }

    // Adicionar pontuação
    function addScore() {
        for (let i = 0; i < 199; i += width) {
            const row = [i, i+1, i+2, i+3, i+4, i+5, i+6, i+7, i+8, i+9];

            if (row.every(index => squares[index].classList.contains('taken'))) {
                score += 10;
                scoreDisplay.innerText = score;
                row.forEach(index => {
                    squares[index].classList.remove('taken');
                    squares[index].style.backgroundColor = '';
                });
                const squaresRemoved = squares.splice(i, width);
                squares = squaresRemoved.concat(squares);
                squares.forEach(cell => grid.appendChild(cell));
            }
        }
    }

    // Verificar o fim do jogo
    function gameOver() {
        if (current.some(index => squares[currentPosition + index].classList.contains('taken'))) {
            scoreDisplay.innerText = 'Fim de jogo';
            clearInterval(timerId);
        }
    }

    document.addEventListener('keyup', control);
    function control(e) {
        if (e.keyCode === 37) {
            moveLeft();
        } else if (e.keyCode === 38) {
            rotate();
        } else if (e.keyCode === 39) {
            moveRight();
        } else if (e.keyCode === 40) {
            moveDown();
        }
    }

    function moveLeft() {
        undraw();
        const isAtLeftEdge = current.some(index => (currentPosition + index) % width === 0);
        if (!isAtLeftEdge) currentPosition -= 1;
        if (current.some(index => squares[currentPosition + index].classList.contains('taken'))) {
            currentPosition += 1;
        }
        draw();
    }

    function moveRight() {
        undraw();
        const isAtRightEdge = current.some(index => (currentPosition + index) % width === width - 1);
        if (!isAtRightEdge) currentPosition += 1;
        if (current.some(index => squares[currentPosition + index].classList.contains('taken'))) {
            currentPosition -= 1;
        }
        draw();
    }

    function rotate() {
        undraw();
        currentRotation++;
        if (currentRotation === current.length) {
            currentRotation = 0;
        }
        current = theTetrominos[random][currentRotation];
        draw();
    }

    document.querySelector('#restart').addEventListener('click', () => {
        clearInterval(timerId);
        score = 0;
        scoreDisplay.innerText = score;
        nextRandom = 0;
        createBoard();
        random = Math.floor(Math.random() * theTetrominos.length);
        current = theTetrominos[random][currentRotation];
        currentPosition = 4;
        draw();
        timerId = setInterval(moveDown, 1000);
    });

    document.querySelector('#pause').addEventListener('click', () => {
        if (timerId) {
            clearInterval(timerId);
            timerId = null;
            document.querySelector('#pause').innerText = 'Retomar';
        } else {
            timerId = setInterval(moveDown, 1000);
            document.querySelector('#pause').innerText = 'Pausar';
        }
    });

    document.querySelector('#reset-score').addEventListener('click', () => {
        score = 0;
        scoreDisplay.innerText = score;
    });
});

  • Variáveis e Seletores: Definem elementos do DOM e variáveis necessárias para o jogo.
  • createBoard(): Cria o tabuleiro do jogo preenchendo-o com células.
  • Tetrominos: Define as formas e rotações dos Tetrominos.
  • Desenho e Movimentação: Funções para desenhar, mover, rotacionar e congelar os Tetrominos.
  • Controle de Teclado: Adiciona eventos de teclado para mover e rotacionar os Tetrominos.
  • Funções de Controle: Funções para reiniciar, pausar e zerar a pontuação do jogo.

Como Executar

  1. Faça o download ou clone este repositório.
  2. Abra o arquivo index.html em um navegador web.
  3. O jogo será carregado e estará pronto para jogar.
  4. Utilize as teclas de seta para mover e rotacionar os Tetrominos:
    • Seta para esquerda: Move o Tetromino para a esquerda.
    • Seta para direita: Move o Tetromino para a direita.
    • Seta para cima: Rotaciona o Tetromino.
    • Seta para baixo: Move o Tetromino para baixo.
  5. Use os botões de controle para reiniciar, pausar e zerar a pontuação do jogo.

Mais Posts

Como instalar o DBEAVEr via PPA no Ubuntu Linux e derivados.

Como instalar o DBEAVEr via PPA no Ubuntu Linux e derivados.

Vamos a mais um post HOW TO…. Abra o Terminal: Você pode fazer isso procurando por “Terminal” no menu de... Leia mais

Como desfazer alterações em arquivos indesejados num Pull Request (PR)

Como desfazer alterações em arquivos indesejados num Pull Request (PR)

Ao criar um Pull Request, é comum perceber depois que um arquivo foi modificado por engano ou não deveria estar... Leia mais

Como Usar a Porta 443 para Conexões SSH com o Bitbucket e Contornar Restrições de Rede

Como Usar a Porta 443 para Conexões SSH com o Bitbucket e Contornar Restrições de Rede

Se você já se deparou com a frustrante mensagem de erro “ssh: connect to host bitbucket.org port 22: Network is... Leia mais

Entendendo o Conceito de Estado no React

Entendendo o Conceito de Estado no React

Em React, o estado refere-se a uma estrutura de dados que determina o comportamento do componente e como ele será... Leia mais