Foco da Matéria: Criar os obstáculos (tubos) dinamicamente com JavaScript, movê-los e, o mais importante, implementar a lógica de detecção de colisão entre o pássaro e os tubos.
1. 🏗️ Criação Dinâmica dos Tubos
Os tubos não estão no HTML, pois eles são criados e destruídos continuamente. Usaremos JavaScript para criar os elementos DOM (div com a classe .pipe) e injetá-los no contêiner do jogo.
Vamos adicionar o código de criação e posicionamento dos tubos ao seu game.js.
JavaScript
// VARIÁVEIS DE CONFIGURAÇÃO (Já definidas no Tema 3)
// const VELOCIDADE_TUBO = 2;
// const INTERVALO_TUBO = 1500;
// VARIÁVEIS DE ESTADO
let tubos = []; // Array para armazenar todos os tubos ativos
// --- FUNÇÃO PARA CRIAR UM PAR DE TUBOS ---
function criarTubo() {
if (!isGameRunning) return;
// 1. Calcular Alturas e Espaço (Gap):
const minHeight = 50; // Altura mínima do tubo
const gapHeight = 120; // Espaço para o pássaro passar
const maxTopPipeHeight = containerHeight - groundHeight - gapHeight - minHeight;
// Altura aleatória para o tubo superior
const topPipeHeight = Math.floor(Math.random() * maxTopPipeHeight) + minHeight;
// Altura do tubo inferior é o restante do espaço disponível
const bottomPipeHeight = containerHeight - groundHeight - topPipeHeight - gapHeight;
// 2. Criar Elementos DOM para o Tubo Superior:
const topPipe = document.createElement('div');
topPipe.classList.add('pipe', 'top');
topPipe.style.height = topPipeHeight + 'px';
topPipe.style.right = '0px'; // Inicia na borda direita
// Adiciona a ponta do tubo (pipe-cap)
const topCap = document.createElement('div');
topCap.classList.add('pipe-cap');
topPipe.appendChild(topCap);
// 3. Criar Elementos DOM para o Tubo Inferior:
const bottomPipe = document.createElement('div');
bottomPipe.classList.add('pipe', 'bottom');
bottomPipe.style.height = bottomPipeHeight + 'px';
bottomPipe.style.right = '0px';
bottomPipe.style.bottom = groundHeight + 'px'; // Posiciona acima do chão
// Adiciona a ponta do tubo
const bottomCap = document.createElement('div');
bottomCap.classList.add('pipe-cap');
bottomPipe.appendChild(bottomCap);
// 4. Adicionar ao Jogo e ao Array:
gameContainer.appendChild(topPipe);
gameContainer.appendChild(bottomPipe);
// Armazena a referência para movimentação e colisão
tubos.push({ top: topPipe, bottom: bottomPipe, passed: false });
}
// Chamar a função de criação a cada INTERVALO_TUBO (no startGame)
let pipeInterval;
function startGame() {
// ... (Código do Tema 3) ...
// Limpa tubos antigos se houver
tubos.forEach(p => {
p.top.remove();
p.bottom.remove();
});
tubos = [];
clearInterval(pipeInterval); // Limpa qualquer intervalo anterior
// Inicia a criação periódica dos tubos
criarTubo(); // Cria o primeiro imediatamente
pipeInterval = setInterval(criarTubo, INTERVALO_TUBO);
// ... (restante do código do Tema 3) ...
}
// Chame startGame() ao final do seu game.js para garantir que inicie.
2. 🏃 Movimento dos Tubos (Dentro do gameLoop)
O movimento dos tubos ocorre dentro do gameLoop() (da lição anterior). Eles se movem da direita para a esquerda.
Atualize a função gameLoop em game.js:
JavaScript
// --- O MOTOR DO JOGO (GAME LOOP) ---
function gameLoop() {
// ... (código da gravidade e atualização da posição do pássaro) ...
// 3. MOVER TUBOS E CHECAR COLISÃO:
const pipesToRemove = [];
tubos.forEach(pipe => {
// Posição X atual do tubo (lida do CSS 'right')
let pipeX = parseFloat(pipe.top.style.right) || 0;
// Move o tubo para a esquerda
pipeX += VELOCIDADE_TUBO;
// Aplica a nova posição (move na tela)
pipe.top.style.right = pipeX + 'px';
pipe.bottom.style.right = pipeX + 'px';
// LÓGICA DE COLISÃO (Próximo Subtópico)
// Verificação de Remoção: Se o tubo saiu da tela (passou da largura do container)
if (pipeX > gameContainer.offsetWidth) {
pipesToRemove.push(pipe);
}
// Lógica de Pontuação: Se o tubo passou do pássaro e ainda não foi contado
const birdLeft = geekBird.offsetLeft;
const pipeRightEdge = gameContainer.offsetWidth - pipeX; // Posição X da borda direita do tubo
if (pipeRightEdge < birdLeft && !pipe.passed) {
score++;
scoreDisplay.textContent = `Pontuação: ${score}`;
pipe.passed = true;
}
});
// Limpa tubos que saíram da tela e os remove do array
pipesToRemove.forEach(pipe => {
pipe.top.remove();
pipe.bottom.remove();
tubos = tubos.filter(p => p !== pipe);
});
// ... (restante do código: Checar Colisão Chão/Teto e requestAnimationFrame) ...
}
3. 💥 Detecção de Colisão (O Coração do Jogo)
A colisão é verificada usando o princípio da “caixa delimitadora” (Bounding Box). O código checa se o pássaro está sobrepondo (fisicamente tocando) a área de um tubo.
Adicione a lógica de colisão DENTRO do tubos.forEach(...) no gameLoop:
JavaScript
// DENTRO DO tubos.forEach(pipe => { ... })
// 1. Coordenadas do Pássaro:
const birdRect = geekBird.getBoundingClientRect();
// 2. Coordenadas dos Tubos:
const topPipeRect = pipe.top.getBoundingClientRect();
const bottomPipeRect = pipe.bottom.getBoundingClientRect();
// 3. Verificação de Colisão (Bounding Box Algorithm):
// Condição de colisão: Verifica se o pássaro está tocando o tubo superior OU o tubo inferior
if (
// Colisão com o tubo superior
(birdRect.left < topPipeRect.right &&
birdRect.right > topPipeRect.left &&
birdRect.top < topPipeRect.bottom) ||
// Colisão com o tubo inferior
(birdRect.left < bottomPipeRect.right &&
birdRect.right > bottomPipeRect.left &&
birdRect.bottom > bottomPipeRect.top)
) {
// COLISÃO DETECTADA!
gameOver();
}
// ... (restante do código de movimento do tubo) ...
(Nota: getBoundingClientRect() é um método do DOM que retorna as coordenadas absolutas e dimensões de um elemento na tela, simplificando a matemática de colisão.)
Com este código, o jogo agora é completamente funcional: o pássaro se move, os tubos aparecem e, se você bater, o jogo acaba!
Deixe um comentárioVocê precisa entrar para publicar um comentário.