Foco da Matéria: Introduzir o conceito de classes em JavaScript para organizar o código do jogo. Em vez de usar variáveis globais e funções dispersas, criaremos classes (Bird, Pipe) que encapsulam suas próprias propriedades e métodos, tornando o código mais limpo e escalável.

1. 💡 Por Que Usar Classes?

À medida que o jogo cresce, o arquivo game.js se torna difícil de gerenciar. A Programação Orientada a Objetos (POO), através do uso de classes, nos permite:

  1. Reutilização de Código: Criar vários inimigos (tubos) a partir de um único molde.
  2. Encapsulamento: Manter as propriedades de um objeto (ex: velocidadeY do pássaro) dentro do próprio objeto, sem poluir o escopo global.

2. 🐦 Criando a Classe Bird

Vamos refatorar a lógica de movimento e pulo do Tema 3 para dentro de uma classe.

Atualize o game.js (Substitua as variáveis de estado e a função pular pelo seguinte):

JavaScript

// VARIÁVEIS DE ESTADO: Moveremos o 'birdY' e 'velocidadeY' para a classe

// --- CLASSE PÁSSARO ---
class Bird {
    constructor(elementId, initialY) {
        this.element = document.getElementById(elementId);
        this.y = initialY; // Posição vertical
        this.velocity = 0; // Velocidade vertical
    }

    // Método que aplica gravidade e atualiza a posição
    applyPhysics() {
        this.velocity += GRAVIDADE;
        this.y += this.velocity;

        // Limita a posição Y (evita que vá para o infinito)
        if (this.y < 0) {
            this.y = 0;
            this.velocity = 0;
        }

        // Atualiza o DOM
        this.element.style.top = this.y + 'px';
    }

    // Método de pulo
    jump() {
        if (isGameRunning) {
            this.velocity = FORCA_PULO;
        }
    }
}

// Inicializa a instância do pássaro
const geekBird = new Bird('geek-bird', 200);

// Substitua a chamada do listener:
document.addEventListener('click', () => geekBird.jump());
document.addEventListener('keydown', (e) => {
    if (e.code === 'Space') {
        geekBird.jump();
    }
});

3. ♻️ Refatorando o gameLoop e gameOver

Agora, precisamos atualizar as funções do jogo para usar o novo objeto geekBird em vez das variáveis globais birdY e velocidadeY.

Atualize as funções startGame, gameLoop e gameOver em game.js:

JavaScript

// --- FUNÇÕES DE CONTROLE (Atualizadas) ---

function startGame() {
    isGameRunning = true;
    score = 0;
    scoreDisplay.textContent = `Pontuação: 0`;
    
    // Reseta o pássaro usando o método da classe
    geekBird.y = 200; 
    geekBird.velocity = 0;
    
    // ... (Limpa tubos antigos e inicia pipeInterval) ...
    
    requestAnimationFrame(gameLoop);
}

function gameLoop() {
    if (!isGameRunning) return;

    // 1. APLICAR FÍSICA NO PÁSSARO (Usando o método da classe)
    geekBird.applyPhysics();

    // 2. CHECAR COLISÃO COM O CHÃO/TETO (Usando geekBird.y)
    const birdHeight = geekBird.element.offsetHeight; // Altura do elemento
    
    if (geekBird.y > containerHeight - birdHeight - groundHeight) {
        geekBird.y = containerHeight - birdHeight - groundHeight;
        geekBird.velocity = 0;
        gameOver(); 
    }
    
    // 3. MOVER TUBOS E CHECAR COLISÃO (Ajustar para usar geekBird.y e element)
    // ... (A lógica de movimentação e colisão permanece a mesma, mas usando geekBird.element e geekBird.y para as checagens)
    
    // ... (restante do código) ...
    
    requestAnimationFrame(gameLoop);
}

// A classe Pipe também poderia ser criada, mas para este jogo simples, refatorar apenas o Bird já demonstra o princípio.

Com essa refatoração, o código está mais limpo, mais fácil de ler e mais preparado para receber novos elementos (como vidas extras ou power-ups) sem causar confusão nas variáveis globais.