space invaders

Criando o Space Invaders – Tutorial em JavaScript

Space Invaders é um clássico jogo de arcade lançado em 1978, desenvolvido por Tomohiro Nishikado. No jogo, o objetivo é controlar uma nave espacial que se move horizontalmente na parte inferior da tela, atirando em uma formação de invasores alienígenas que descem gradualmente. É um marco da indústria dos videogames, e sua recriação em JavaScript é uma maneira perfeita de praticar e aprender a programação de jogos e reviver essa lenda dos arcades!

Acesse o code.org, ao entrar na sua conta, selecione a opção criar novo projeto e escolha “game lab”.

labirinto

Passo 1: Configurando as Variáveis

Aqui, vamos criar o nosso jogador, os grupos de inimigos e balas, além de variáveis que vão acompanhar as vidas e pontos do jogador.

				
					// variável jogador e animação
var jogador = createSprite(169, 359, 20, 20);
jogador.setAnimation("nave");
jogador.scale = 0.5;

//variáveis grupos inimigos
var grupoinimigo = createGroup();
var grupoinimigo2 = createGroup();
var grupoinimigo3 = createGroup();
var grupobullet = createGroup();

//variáveis hud
var life = 3;
var Points = 0;

//variável estado de jogo
var gamestate = "iniciar";

				
			

Dica Pro: Lembre-se de criar as animações para deixar seu jogo mais atrativo!

labirinto
space invaders

Passo 2: Controles do jogador

Damos ao jogador controle total para mover a nave para os lados, atirar balas e, claro, manter-se vivo enquanto enfrenta ondas de inimigos!

				
					//movimento do jogador
if (keyDown("left")) {
  jogador.x -= 5;
}
if (keyDown("right")) {
  jogador.x += 5;
}

//impedindo que o jogador saia da tela
  if(jogador.x>363){
    jogador.x=363;
  }
  
   if(jogador.x<37){
    jogador.x=37;
  }
  
//disparando as bullets
if (keyWentDown("space")) {
  criarbullet();
}
				
			

Passo 3: Criando as bullets

Vamos dar ao jogador a habilidade de atirar balas! Toda vez que o jogador pressionar a barra de espaço, uma nova bala será criada e adicionada ao grupo de balas.

				
					// Função para criar uma bala
function criarbullet() {
  var bullet = createSprite(jogador.x, jogador.y, 10, 20);
  bullet.shapeColor = 'blue';
  //atribuindo velocidade a bala
  bullet.velocityY = -10;
  grupobullet.add(bullet); // Adiciona a bala ao grupo
}
				
			

Solução Inteligente: Notou como o grupobullet.add(bullet) facilita a gestão das balas? Assim, fica super fácil manipular todas as balas como um único conjunto.

space invaders

Passo 4: Criando os inimigos

A cada intervalo de tempo, novos inimigos aparecerão na tela!

				
					// Função para criar inimigos
function criarinimigo1() {
  if (frameCount % 60 == 0) {
    var inimigo = createSprite(random(50, 370), 28, 20, 20);
    inimigo.setAnimation("inimigo1");
    inimigo.scale = 0.10;
    inimigo.velocityY = 4;
    inimigo.lifetime = 100;
    grupoinimigo.add(inimigo);
  }
}

				
			

Passo 5: Implementando a Colisão entre o Jogador e os Inimigos

Vamos implementar as colisões, ou seja, quando o jogador colidir com um inimigo, algo épico vai acontecer: a vida do jogador será reduzida e o inimigo será eliminado da tela!

				
					// Verificando a colisão entre o jogador e os inimigos
for (var x = 0; x < grupoinimigo3.length; x++) {
    if (jogador.isTouching(grupoinimigo3[x])) {
        // Controla a vida do jogador ao ser atingido
        lifecontrol(); 
        
        // Destroi o inimigo que colidiu
        grupoinimigo3[x].destroy();
    }
}
				
			

Passo 6: Gerenciando vidas do jogador

A função lifecontrol() é bem simples, mas super poderosa! Ela faz o controle das vidas do jogador e define se ele ainda pode continuar jogando ou se perdeu o jogo.

				
					function lifecontrol (){
  life = life - 1;  // Reduzimos a vida do jogador

  if(life >= 1){    // Verifica se o jogador ainda tem vidas
    gamestate = "iniciar";  // Se sim, reiniciamos o jogo
  }
  else {
    gamestate = "perdeu";  // Caso contrário, o jogador perdeu 
  }
}

				
			

Passo 7: Destruindo os Inimigos com as bullets do Jogador

No código, utilizamos um laço duplo para verificar se cada bala está colidindo com um dos inimigos. Quando essa colisão acontece, tanto a bala quanto o inimigo são destruídos, e o jogador ganha pontos!

				
					// Laço externo: percorre todos os inimigos no grupo inimigo3
for (var x = 0; x < grupoinimigo3.length; x = x + 1) {
  
  // Laço interno: percorre todas as balas no grupo de balas (grupobullet)
  for (var y = 0; y < grupobullet.length; y = y + 1) {
    
    // Verifica se o inimigo e a bala existem e se estão se tocando
    if (grupoinimigo3[x] && grupobullet[y] && grupobullet[y].isTouching(grupoinimigo3[x])) {
      
      // Se a colisão for detectada, destrói o inimigo
      grupoinimigo3[x].destroy();
      
      // Também destrói a bala
      grupobullet[y].destroy();
      
      // Incrementa os pontos do jogador ao destruir um inimigo
      Points = Points + 10;
    }
  }
}

				
			

Passo 8: Configurando o Estado Inicial do Jogo com a Função iniciar()

No desenvolvimento de jogos, um dos conceitos mais importantes é o estado do jogo. Ele define o que está acontecendo no jogo em cada momento: se estamos jogando, na tela de pausa, ou aguardando o início da partida. Neste passo do tutorial, vamos falar sobre a função iniciar() e como ela organiza o jogo antes de tudo começar.

				
					function iniciar() {
  
  // Pausa os inimigos, impedindo que eles se movam
  grupoinimigo.setVelocityYEach(0);
  grupoinimigo2.setVelocityYEach(0);
  grupoinimigo3.setVelocityYEach(0);
  
  // Define a posição inicial da nave do jogador no centro da tela
  jogador.x = 200;
  jogador.y = 350;
  
  // Exibe uma mensagem para o jogador saber como iniciar o jogo
  textSize(30);
  fill("red");
  textFont("Aptos Black");
  text("clique UP para iniciar", 90, 200);
  
  // Remove todos os inimigos da tela (se houver algum restante)
  grupoinimigo.destroyEach();
  grupoinimigo2.destroyEach();
  grupoinimigo3.destroyEach();
  
  // Verifica se a tecla "UP" foi pressionada para mudar o estado do jogo para "jogar"
  if (keyDown("up")) {
    gamestate = "jogar";
  }
  
}

				
			

Passo 9: Implementando a Função Principal do Jogo com jogar()

Agora que já configuramos o início do jogo e o comportamento dos inimigos, vamos falar sobre a função que comanda a ação enquanto o jogo está em andamento: a função jogar(). É aqui que a verdadeira batalha espacial acontece! 

A função jogar() controla o movimento da nave do jogador, a criação de inimigos, o disparo de balas e a detecção de colisões entre balas e inimigos.

				
					function jogar() {

  // Limita o movimento da nave do jogador para que não saia da tela
  if(jogador.x > 363) {
    jogador.x = 363;
  }
  
  if(jogador.x < 37) {
    jogador.x = 37;
  }

  // Cria os inimigos regularmente
  criarinimigo1();
  criarinimigo2();
  criarinimigo3();
  
  // Controles do jogador
  if (keyDown("left")) {
    jogador.x -= 5; // Move a nave para a esquerda
  }

  if (keyDown("right")) {
    jogador.x += 5; // Move a nave para a direita
  }
  
  // Cria uma bala quando a barra de espaço é pressionada
  if (keyWentDown("space")) {
    criarbullet();
  }

  // Verifica se as balas atingem os inimigos do grupo inimigo1 e os destroem
  for (var x = 0; x < grupoinimigo.length; x = x + 1) {
    for (var y = 0; y < grupobullet.length; y = y + 1) {
      if (grupoinimigo[x] && grupobullet[y] && grupobullet[y].isTouching(grupoinimigo[x])) {
        grupoinimigo[x].destroy();
        grupobullet[y].destroy();
        Points += 10; // Adiciona 10 pontos ao destruir um inimigo
      }
    }
  }

  // Verifica se as balas atingem os inimigos do grupo inimigo2 e os destroem
  for (var x = 0; x < grupoinimigo2.length; x = x + 1) {
    for (var y = 0; y < grupobullet.length; y = y + 1) {
      if (grupoinimigo2[x] && grupobullet[y] && grupobullet[y].isTouching(grupoinimigo2[x])) {
        grupoinimigo2[x].destroy();
        grupobullet[y].destroy();
        Points += 10; // Adiciona 10 pontos ao destruir um inimigo
      }
    }
  }

  // Verifica se as balas atingem os inimigos do grupo inimigo3 e os destroem
  for (var x = 0; x < grupoinimigo3.length; x = x + 1) {
    for (var y = 0; y < grupobullet.length; y = y + 1) {
      if (grupoinimigo3[x] && grupobullet[y] && grupobullet[y].isTouching(grupoinimigo3[x])) {
        grupoinimigo3[x].destroy();
        grupobullet[y].destroy();
        Points += 10; // Adiciona 10 pontos ao destruir um inimigo
      }
    }
  }

  // Verifica se o jogador foi atingido por algum inimigo do grupo inimigo1
  for (var x = 0; x < grupoinimigo.length; x = x + 1) {
    if (jogador.isTouching(grupoinimigo[x])) {
      lifecontrol(); // Reduz a vida do jogador
      grupoinimigo[x].destroy(); // Destroi o inimigo ao tocar o jogador
    }
  }

  // Verifica se o jogador foi atingido por algum inimigo do grupo inimigo2
  for (var x = 0; x < grupoinimigo2.length; x = x + 1) {
    if (jogador.isTouching(grupoinimigo2[x])) {
      lifecontrol(); // Reduz a vida do jogador
      grupoinimigo2[x].destroy(); // Destroi o inimigo ao tocar o jogador
    }
  }

  // Verifica se o jogador foi atingido por algum inimigo do grupo inimigo3
  for (var x = 0; x < grupoinimigo3.length; x = x + 1) {
    if (jogador.isTouching(grupoinimigo3[x])) {
      lifecontrol(); // Reduz a vida do jogador
      grupoinimigo3[x].destroy(); // Destroi o inimigo ao tocar o jogador
    }
  }
}

				
			

Passo 10: Implementando o Fim de Jogo com a Função perdeu()

Agora vamos falar sobre uma parte inevitável de qualquer jogo: o fim de jogo. Em nosso Space Invaders, quando o jogador perde todas as suas vidas, entramos no estado “perdeu”. É aqui que a função perdeu() entra em ação! 

Essa função exibe uma mensagem para o jogador informando que ele perdeu e oferece a opção de reiniciar o jogo pressionando a tecla “R”. Além disso, ela garante que todos os inimigos sejam removidos da tela, criando uma pausa antes de reiniciar.

				
					function perdeu() {
    
    // Define o tamanho e a cor do texto
    textSize(20);
    fill("red");
    textFont("Aptos Black");
    
    // Exibe a mensagem de fim de jogo
    text("Você perdeu, clique em R para reiniciar", 50, 200);
    
    // Remove todos os inimigos da tela
    grupoinimigo.destroyEach();
    grupoinimigo2.destroyEach();
    grupoinimigo3.destroyEach();
    
    // Verifica se a tecla "R" foi pressionada para reiniciar o jogo
    if (keyDown("r")) {
      gamestate = "restart"; // Muda o estado do jogo para "restart"
    }
  
}

				
			
reiniciar

Passo 11: Implementando a Função de Reiniciar o Jogo com reiniciar()

Agora que já configuramos o fim de jogo com a função perdeu(), vamos criar a função responsável por reiniciar o jogo

Quando o jogador perde e pressiona a tecla “R”, a função reiniciar() é chamada. Ela reseta as principais variáveis do jogo, como as vidas e os pontos, e coloca o jogo de volta no estado “iniciar”, pronto para um novo começo.

 

				
					function reiniciar() {
    // Reseta a quantidade de vidas para o valor inicial
    life = 3;
    
    // Reseta a pontuação do jogador para 0
    Points = 0;
    
    // Muda o estado do jogo para "iniciar", preparando o jogo para um novo começo
    gamestate = "iniciar";
}

				
			

Passo 12: Desenhando e Controlando o Fluxo do Jogo com a Função draw()

A função draw() é chamada repetidamente a cada quadro do jogo e é responsável por desenhar todos os elementos na tela, como a pontuação, as vidas do jogador e os sprites, além de controlar o estado do jogo. Dependendo do estado atual, ela chama as funções correspondentes para iniciar, jogar, perder ou reiniciar o jogo.

				
					function draw() {
  // Define o fundo preto para o jogo
  background("black");
  
  // Atualiza o desenho dos sprites na tela
  drawSprites();
  
  // Exibe a quantidade de vidas do jogador na tela
  textSize(40);
  fill("red");
  textFont("Aptos Black");
  text("vida: " + life, 20, 368);
  
  // Exibe a pontuação do jogador na tela
  fill("white");
  text("Points: " + Points, 116, 32);
 
  
  // Verifica o estado do jogo e chama a função correspondente
  if (gamestate == "iniciar") {
    iniciar(); // Chama a função que prepara o jogo para iniciar
  }
  
  if (gamestate == "jogar") {
    jogar(); // Chama a função que controla o jogo durante a ação
  }
  
  if (gamestate == "perdeu") {
    perdeu(); // Chama a função que trata o fim de jogo
  }
  
  if (gamestate == "reiniciar") {
    reiniciar(); // Chama a função que reinicia o jogo
  }
}

				
			

RESULTADO

space invaders
				
					// Variáveis
var jogador = createSprite(169, 359, 20, 20);
jogador.setAnimation("nave");
jogador.scale = 0.5;

var grupoinimigo = createGroup();
var grupoinimigo2 = createGroup();
var grupoinimigo3 = createGroup();
var grupobullet = createGroup();

var life = 3;
var Points = 0;
var gamestate = "iniciar";

var inimigo, inimigo2, inimigo3;

// Função desenhar - ocorre a todo momento
function draw() {
  background("black");
  
  // Atualiza o desenho dos sprites
  drawSprites();
  
  // Exibe vidas e pontuação
  textSize(40);
  fill("red");
  textFont("Aptos Black");
  text("vida: " + life, 20, 368);
  fill("white");
  text("Points: " + Points, 116, 32);
  
  // Controle do fluxo do jogo baseado no estado
  if (gamestate == "iniciar") {
    iniciar();
  }
  
  if (gamestate == "jogar") {
    jogar();
  }
  
  if (gamestate == "perdeu") {
    perdeu();
  }
  
  if (gamestate == "reiniciar") {
    reiniciar();
  }
}

// Função para criar uma bala
function criarbullet() {
  var bullet = createSprite(jogador.x, jogador.y, 10, 20);
  bullet.shapeColor = 'blue';
  bullet.velocityY = -10;
  bullet.lifetime = 100;
  grupobullet.add(bullet);
}

// Funções para criar inimigos
function criarinimigo1() {
  if (frameCount % 60 === 0) {
    inimigo = createSprite(random(50, 370), 28, 20, 20);
    inimigo.setAnimation("inimigo1");
    inimigo.scale = 0.10;
    inimigo.velocityY = 4;
    inimigo.lifetime = 100;
    grupoinimigo.add(inimigo);
  }
}

function criarinimigo2() {
  if (frameCount % 90 === 0) {
    inimigo2 = createSprite(random(50, 370), 28, 20, 20);
    inimigo2.setAnimation("inimigo2");
    inimigo2.scale = 0.10;
    inimigo2.velocityY = 4;
    inimigo2.lifetime = 100;
    grupoinimigo2.add(inimigo2);
  }
}

function criarinimigo3() {
  if (frameCount % 90 === 0) {
    inimigo3 = createSprite(random(50, 370), 28, 20, 20);
    inimigo3.setAnimation("inimigo3");
    inimigo3.scale = 0.10;
    inimigo3.velocityY = 4;
    inimigo3.lifetime = 100;
    grupoinimigo3.add(inimigo3);
  }
}

// Função para controle de vida
function lifecontrol() {
  life -= 1;
  if (life >= 1) {
    gamestate = "iniciar";
  } else {
    gamestate = "perdeu";
  }
}

// Função para iniciar o jogo
function iniciar() {
  grupoinimigo.setVelocityYEach(0);
  grupoinimigo2.setVelocityYEach(0);
  grupoinimigo3.setVelocityYEach(0);
  
  jogador.x = 200;
  jogador.y = 350;
  
  textSize(30);
  fill("red");
  textFont("Aptos Black");
  text("clique UP para iniciar", 90, 200);
  
  grupoinimigo.destroyEach();
  grupoinimigo2.destroyEach();
  grupoinimigo3.destroyEach();
  
   // Transição para estado "jogar" ao pressionar "UP"
  if (keyDown("up")) {
    gamestate = "jogar";
  }
  
}

// Função para jogar
function jogar() {
  if (jogador.x > 363) {
    jogador.x = 363;
  }
  
  if (jogador.x < 37) {
    jogador.x = 37;
  }
  
  criarinimigo1();
  criarinimigo2();
  criarinimigo3();
  
  if (keyDown("left")) {
    jogador.x -= 5;
  }
  
  if (keyDown("right")) {
    jogador.x += 5;
  }
  
  if (keyWentDown("space")) {
    criarbullet();
  }
  
  // Verifica se as balas atingem os inimigos e os destroem
  for (var x = 0; x < grupoinimigo.length; x++) {
    for (var y = 0; y < grupobullet.length; y++) {
      if (grupoinimigo[x] && grupobullet[y] && grupobullet[y].isTouching(grupoinimigo[x])) {
        grupoinimigo[x].destroy();
        grupobullet[y].destroy();
        Points += 10;
      }
    }
  }
  
  for (var x = 0; x < grupoinimigo2.length; x++) {
    for (var y = 0; y < grupobullet.length; y++) {
      if (grupoinimigo2[x] && grupobullet[y] && grupobullet[y].isTouching(grupoinimigo2[x])) {
        grupoinimigo2[x].destroy();
        grupobullet[y].destroy();
        Points += 10;
      }
    }
  }
  
  for (var x = 0; x < grupoinimigo3.length; x++) {
    for (var y = 0; y < grupobullet.length; y++) {
      if (grupoinimigo3[x] && grupobullet[y] && grupobullet[y].isTouching(grupoinimigo3[x])) {
        grupoinimigo3[x].destroy();
        grupobullet[y].destroy();
        Points += 10;
      }
    }
  }
  
  // Verifica se os inimigos tocam o jogador e ajusta a vida
  for (var x = 0; x < grupoinimigo.length; x++) {
    if (jogador.isTouching(grupoinimigo[x])) {
      lifecontrol();
      grupoinimigo[x].destroy();
    }
  }
  
  for (var x = 0; x < grupoinimigo2.length; x++) {
    if (jogador.isTouching(grupoinimigo2[x])) {
      lifecontrol();
      grupoinimigo2[x].destroy();
    }
  }
  
  for (var x = 0; x < grupoinimigo3.length; x++) {
    if (jogador.isTouching(grupoinimigo3[x])) {
      lifecontrol();
      grupoinimigo3[x].destroy();
    }
  }
}

// Função para fim de jogo
function perdeu() {

    textSize(20);
    fill("red");
    textFont("Aptos Black");
    text("Você perdeu, clique em R para reiniciar", 50, 200);
    
    grupoinimigo.destroyEach();
    grupoinimigo2.destroyEach();
    grupoinimigo3.destroyEach();
    
    if (keyDown("r")) {
      gamestate = "restart";
    }
  
}

// Função para reiniciar o jogo
function reiniciar() {
  
    life = 3;
    Points = 0;
    gamestate = "iniciar";
  
}

				
			

Posts Similares

1 Comentário

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *