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 RabbitVCS no ubuntu 18.04

Como instalar o RabbitVCS no ubuntu 18.04

Caso você sendo usuário Linux e precise instalar um gerenciador de SVN temos como alternativa o RABBITVCS. São apenas dois... Leia mais

Usando a Função ROW_NUMBER e Outras Funções para Gerar Resultados Sequenciais no PostgreSQL

Usando a Função ROW_NUMBER e Outras Funções para Gerar Resultados Sequenciais no PostgreSQL

Quando trabalhamos com bancos de dados, muitas vezes precisamos gerar números sequenciais para nossos resultados. Isso pode ser útil para... Leia mais

Entendendo as Diferenças Entre Programação Orientada a Objetos e Funcional: Java vs. Elixir

Entendendo as Diferenças Entre Programação Orientada a Objetos e Funcional: Java vs. Elixir

A escolha entre programação orientada a objetos (OOP) e programação funcional (FP) é mais do que uma preferência de estilo;... 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