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

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

Convenção de nomes utilizada no Laravel

Convenção de nomes utilizada no Laravel

Tabela para consulta rápida a convenção de nomes utilizadas em projetos Laravel: Leia mais

Habilitar Sudo no Debian e seus derivados

Habilitar Sudo no Debian e seus derivados

Por padrão o debian não trás o sudo habilitado como estamos acostumados no Ubuntu e outro de seus derivados como... Leia mais

Solucionando Problemas de Conexão no PostgreSQL: Um Guia Prático

Solucionando Problemas de Conexão no PostgreSQL: Um Guia Prático

Quando se trata de gerenciar bancos de dados, o PostgreSQL se destaca como uma escolha robusta e flexível para desenvolvedores... Leia mais