Home > Blog > Projetos Práticos
Projetos Práticos
Desenvolvimento Web
JavaScript
Programação

Jogo em JavaScript: Como Criar um Jogo de Nave Espacial

Atualizado em: 19 de dezembro de 2024

foto de um videogame do Pac-Man

Quer aprender a criar um jogo em JavaScript do zero? Neste post, vamos guiá-lo na construção de um jogo de nave espacial utilizando HTML5 Canvas e JavaScript puro. Ao final, você terá uma nave que atira, enfrenta inimigos e reinicia o jogo com um simples toque na tecla “ENTER”.

Se preferir visualizar o jogo em ação antes de começar, confira nosso projeto no CodePen.

O que Você Vai Aprender

  1. Como usar a tag <canvas> para desenhar elementos do jogo.
  2. Movimentar objetos na tela com eventos de teclado.
  3. Criar colisões entre objetos no jogo.
  4. Gerenciar estados como “Game Over” e reinício.
  5. Trabalhar com classes no JavaScript para organizar seu código.

Estrutura Inicial do Jogo

Vamos começar com o básico: criar o HTML e o CSS para exibir o jogo e configurar o espaço onde o jogo será renderizado.

HTML

HTML
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Jogo em JavaScript</title>
    <style>
        body { 
            margin: 0; 
            overflow: hidden; 
            background-color: black; 
            display: flex; 
            justify-content: center; 
            align-items: center; 
            height: 100vh;
            font-family: Arial, sans-serif;
        }
        canvas { 
            border: 2px solid white; 
            background-color: #111; 
        }
        #pontuacao {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            font-size: 20px;
        }
    </style>
</head>
<body>
    <div id="pontuacao">Pontuação: 0</div>
    <canvas id="tela-jogo" width="800" height="600"></canvas>
</body>
</html>

Neste código, criamos:

  • A tag <canvas> para renderizar o jogo.
  • Um contador de pontuação para exibir os pontos acumulados.
  • Um arquivo externo jogo.js onde a lógica do jogo será implementada.

CSS

Adicionamos estilos básicos para:

  • Configurar um fundo escuro que simula o espaço.
  • Centralizar o jogo na tela.
  • Criar um visual limpo com bordas no canvas.

Implementando o Jogo com JavaScript

Agora, vamos criar a lógica do jogo no arquivo jogo.js. Ele será responsável por movimentar a nave, criar inimigos e gerenciar os tiros.

JavaScript

A nave e os inimigos serão desenhados no canvas usando a API CanvasRenderingContext2D.

JavaScript
 // Obter elementos do DOM para uso no jogo
const tela = document.getElementById('tela-jogo');
const contexto = tela.getContext('2d');
const elementoPontuacao = document.getElementById('pontuacao');

// Dimensões e configurações iniciais do jogo
const LARGURA_JOGADOR = 40; // Largura do jogador
const ALTURA_JOGADOR = 40; // Altura do jogador
const LARGURA_INIMIGO = 40; // Largura dos inimigos
const ALTURA_INIMIGO = 40; // Altura dos inimigos

// Objeto principal do estado do jogo
const jogo = {
    jogador: {
        x: tela.width / 2 - LARGURA_JOGADOR / 2, // Posição inicial horizontal
        y: tela.height - ALTURA_JOGADOR - 10, // Posição inicial vertical
        velocidade: 5, // Velocidade do jogador
        tiros: [], // Lista de tiros do jogador
        pontuacao: 0 // Pontuação inicial
    },
    inimigos: [], // Lista de inimigos
    teclas: {}, // Controle das teclas pressionadas
    gameOver: false // Estado inicial do jogo
};

// Classe para gerenciar tiros (do jogador e dos inimigos)
class Tiro {
    constructor(x, y, ehInimigo = false) {
        this.x = x; // Posição horizontal do tiro
        this.y = y; // Posição vertical do tiro
        this.largura = 5; // Largura do tiro
        this.altura = 10; // Altura do tiro
        this.velocidade = ehInimigo ? 4 : -7; // Velocidade diferente para tiros inimigos e do jogador
        this.ehInimigo = ehInimigo; // Define se é um tiro inimigo
    }

    // Desenha o tiro na tela
    desenhar() {
        contexto.fillStyle = this.ehInimigo ? 'red' : 'white';
        contexto.fillRect(this.x, this.y, this.largura, this.altura);
    }

    // Atualiza a posição do tiro
    mover() {
        this.y += this.velocidade;
    }
}

// Classe para gerenciar os inimigos
class Inimigo {
    constructor() {
        this.x = Math.random() * (tela.width - LARGURA_INIMIGO); // Posição inicial aleatória
        this.y = 0; // Começa no topo da tela
        this.velocidade = Math.random() * 2 + 1; // Velocidade aleatória
        this.intervaloTiro = Math.random() * 100 + 50; // Intervalo aleatório para atirar
        this.contadorTiro = 0; // Contador para controlar tiros
    }

    // Desenha o inimigo na tela
    desenhar() {
        contexto.fillStyle = 'red';
        contexto.fillRect(this.x, this.y, LARGURA_INIMIGO, ALTURA_INIMIGO);
    }

    // Move o inimigo para baixo e atira periodicamente
    mover() {
        this.y += this.velocidade;
        this.contadorTiro++;
        if (this.contadorTiro >= this.intervaloTiro) {
            this.atirar();
            this.contadorTiro = 0;
        }
    }

    // Faz o inimigo atirar
    atirar() {
        jogo.jogador.tiros.push(new Tiro(this.x + LARGURA_INIMIGO / 2, this.y + ALTURA_INIMIGO, true));
    }
}

// Função para desenhar o jogador
function desenharJogador() {
    contexto.fillStyle = 'blue';
    contexto.fillRect(jogo.jogador.x, jogo.jogador.y, LARGURA_JOGADOR, ALTURA_JOGADOR);
}

// Move o jogador com base nas teclas pressionadas (somente se o jogo não estiver em game over)
function moverJogador() {
    if (jogo.gameOver) return; // Impede movimentação em Game Over

    if ((jogo.teclas['ArrowLeft'] || jogo.teclas['a']) && jogo.jogador.x > 0) {
        jogo.jogador.x -= jogo.jogador.velocidade;
    }
    if ((jogo.teclas['ArrowRight'] || jogo.teclas['d']) && jogo.jogador.x < tela.width - LARGURA_JOGADOR) {
        jogo.jogador.x += jogo.jogador.velocidade;
    }
    if ((jogo.teclas['ArrowUp'] || jogo.teclas['w']) && jogo.jogador.y > 0) {
        jogo.jogador.y -= jogo.jogador.velocidade;
    }
    if ((jogo.teclas['ArrowDown'] || jogo.teclas['s']) && jogo.jogador.y < tela.height - ALTURA_JOGADOR) {
        jogo.jogador.y += jogo.jogador.velocidade;
    }
}

// O jogador atira ao pressionar espaço (somente se não estiver em game over)
function atirar() {
    if (!jogo.gameOver) {
        jogo.jogador.tiros.push(new Tiro(jogo.jogador.x + LARGURA_JOGADOR / 2, jogo.jogador.y));
    }
}

// Atualiza a posição dos tiros e verifica colisões
function atualizarTiros() {
    jogo.jogador.tiros = jogo.jogador.tiros.filter(tiro => {
        tiro.mover();

        // Colisão com inimigos
        if (!tiro.ehInimigo) {
            jogo.inimigos = jogo.inimigos.filter(inimigo => {
                if (verificarColisao(tiro, inimigo)) {
                    jogo.jogador.pontuacao += 10;
                    elementoPontuacao.textContent = `Pontuação: ${jogo.jogador.pontuacao}`;
                    return false;
                }
                return true;
            });
        }

        // Colisão de tiros inimigos com o jogador
        if (!jogo.gameOver && tiro.ehInimigo && verificarColisao(tiro, jogo.jogador)) {
            jogo.gameOver = true; // Ativa o estado de Game Over
        }
        return tiro.y > 0 && tiro.y < tela.height;
    });
}

// Verifica colisão entre dois objetos retangulares
function verificarColisao(objeto1, objeto2) {
    return !(objeto1.x > objeto2.x + LARGURA_INIMIGO ||
        objeto1.x + objeto1.largura < objeto2.x ||
        objeto1.y > objeto2.y + ALTURA_INIMIGO ||
        objeto1.y + objeto1.altura < objeto2.y);
}

// Atualiza a posição dos inimigos
function atualizarInimigos() {
    if (!jogo.gameOver) {
        if (Math.random() < 0.02) {
            jogo.inimigos.push(new Inimigo());
        }
        jogo.inimigos = jogo.inimigos.filter(inimigo => {
            inimigo.mover();
            return inimigo.y <= tela.height;
        });
    }
}

// Desenha todos os elementos na tela
function desenhar() {
    contexto.clearRect(0, 0, tela.width, tela.height);
    desenharJogador();
    jogo.jogador.tiros.forEach(tiro => tiro.desenhar());
    jogo.inimigos.forEach(inimigo => inimigo.desenhar());

    // Exibe a mensagem de game over se o jogo acabou
    if (jogo.gameOver) {
        contexto.fillStyle = 'rgba(0, 0, 0, 0.5)';
        contexto.fillRect(0, 0, tela.width, tela.height);
        contexto.fillStyle = 'red';
        contexto.font = '48px Arial';
        contexto.textAlign = 'center';
        contexto.fillText('GAME OVER', tela.width / 2, tela.height / 2);
        contexto.font = '20px Arial';
        contexto.fillText(`Pontuação: ${jogo.jogador.pontuacao}`, tela.width / 2, tela.height / 2 + 40);
        contexto.fillText('Pressione ENTER para reiniciar', tela.width / 2, tela.height / 2 + 80);
    }
}

// Ciclo principal do jogo
function loopJogo() {
    moverJogador();
    atualizarTiros();
    atualizarInimigos();
    desenhar();
    requestAnimationFrame(loopJogo);
}

// Reinicia o estado do jogo
function reiniciarJogo() {
    jogo.jogador.x = tela.width / 2 - LARGURA_JOGADOR / 2;
    jogo.jogador.y = tela.height - ALTURA_JOGADOR - 10;
    jogo.jogador.tiros = [];
    jogo.inimigos = [];
    jogo.jogador.pontuacao = 0;
    elementoPontuacao.textContent = 'Pontuação: 0';
    jogo.gameOver = false; // Desativa o estado de Game Over
}

// Eventos para controle do teclado
window.addEventListener('keydown', (evento) => {
    jogo.teclas[evento.key] = true;
    if (evento.key === 'Enter' && jogo.gameOver) reiniciarJogo(); // Reinicia o jogo com ENTER
    if (evento.key === ' ' && !jogo.gameOver) atirar(); // Atira com ESPAÇO
});

window.addEventListener('keyup', (evento) => {
    jogo.teclas[evento.key] = false;
});

// Inicia o loop principal
loopJogo();

Conclusão do Jogo em JavaScript

Com os passos acima, você terá um jogo funcional. Todo o código do jogo foi projetado para ser simples, mas com várias possibilidades de expansão, como incluir power-ups ou diferentes níveis de dificuldade.

Para ver o jogo completo em ação, acesse nosso CodePen com o jogo.

Gostou do tutorial? Deixe sua opinião nos comentários e compartilhe seu progresso com a gente!

Ranking dos 10 Melhores Cursos de Programação de 2025

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

Os comentários estão desativados.

POSTS RELACIONADOS

Ver todos

Seta para a direita

Quer se Tornar um Programador de Sucesso?

Descubra os melhores cursos de programação para acelerar sua carreira e aprender do jeito certo!