Como criar o jogo da cobrinha (snake) usando P5.js

Como criar o jogo da cobrinha (snake) usando P5.js

Nesse post, vamos entender como criar jogo da cobrinha usando o P5js, um framework escrito em javascript especificamente para controle de interface. Para esse projeto, vamos configurar nosso ambiente, criar nosso servidor de visualização, instalar dependências, e codificar do zero esse game.

Antes de mais nada preciso avisar você que esse game não é uma novidade na internet. Logicamente, vários outros criadores de conteúdo já quebraram a cabeça criando esse mini-game inclusive usando outras linguagens ou até mesmo usando apenas Javascript puro. Quer alguns exemplos muito bons? veja uma breve lista a seguir:

Além disso, existe um vídeo em especial que gostaria de recomendar: IA jogando snake . Esse vídeo mostra como transformar projetos simples como esse que vamos codificar em projetos incríveis de inteligência artificial realmente incríveis.

Caso você goste de projetos de jogos como esse, não esqueça de acessar nossa seção de jogos do site. Lá você encontra jogos simples e codificados didáticamente para você aprender conosco.

Organizando o ambiente de desenvolvimento do P5js

O ambiente de desenvolvimento que você vai usar é algo muito pessoal, cada um gosta de desenvolver de um jeito. Porém, vou mostrar aqui como eu fiz para desenvolver esse projeto e também dar algumas opções para você ter menos trabalho caso não queira se preocupar tanto com o ambiente.

Usando o VScode

O VScode é incrível para desenvolvimento Javascript e possui uma ampla gama de opções de Plugins. Além disso, a cereja do bolo é que ele possui uma opção de subir um servidor web local com apenas um clique. Bom, mas antes de mostrar isso precisamos instalar o VScode do site oficial da Microsoft:

Download do VScode

Depois de instalado, você pode baixar um plugin bem legal dentro do próprio VScode que é o P5.vscode. Ele permite que você crie um novo projeto e também adicione pacotes conhecidos para o P5.

Imagem do plugin. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Depois de instalado você pode usar o comando CTRL + SHIFT + P e localizar no terminal dois comandos:

Comandos disponíveis no VScode para o P5.js
Opções dadas pelo plugin instalado. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Ao criar um projeto usando P5.js é requisitado que você selecione uma pasta para criar os arquivos básicos do projeto. Depois de criado, você verá alguns arquivos:

estrutura de arquivos do projeto
Estrutura de arquivos e pasta do projeto inicial P5js. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Por fim, você pode clicar na opção “Go live Server” e você verá uma página da web com seu projeto sendo executado.

Usando o ambiente web

Caso você não queira ter todo esse trabalho de configuração, você pode simplesmente usar o editor web do P5.js disponível nesse link. Esse editor permite criar e visualizar seu projeto de forma bastante simples e rápida, você só precisa do seu navegador.

Se você desejar salvar seus projetos, crie uma conta no ambiente e você terá a possibilidade de criar novos arquivos, usar bibliotecas dentre outras funções bem legais.

Iniciando o desenvolvimento do jogo da cobrinha

O primeiro passo depois de inicializar nosso ambiente é criar a função setup e draw:

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(51);
}

Essas funções já são padrão do P5.js, então com essas funções você já observa um resultado mínimo em sua tela. Depois disso, podemos desenhar nosso personagem principal, a nossa cobrinha. Para isso vamos apenas mostrar um retângulo na tela, o que seria algo mais ou menos assim:

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(51);
  rect(200,200,10,10)
}

O resultado será algo mais ou menos assim:

primeiro preview da cobrinha
Primeira aparição da nossa “cobrinha”. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Perfeito, agora podemos adicionar um pouco de movimento para nossa cobrinha… para isso precisamos colocar em nossa função draw() alguns comandos que façam nossa cobra se movimentar em algum dos eixos:

 // variáveis da cobrinha
 let xCobra = 50;
 let yCobra = 40;
 let wCobra = 10;
 let hCobra = 10;

// velocidade da movimentação
 let velocidadeMovimentacao = 5;

 function setup() {
   createCanvas(400, 400);
 }

 function draw() {
   background(51);
   rect(xCobra, yCobra, wCobra, hCobra);
// adiciona comandos para as setinhas
 if (keyIsDown(LEFT_ARROW)) {
     xCobra -= velocidadeMovimentacao;
   }
 if (keyIsDown(RIGHT_ARROW)) {
     xCobra += velocidadeMovimentacao;
   }
 if (keyIsDown(UP_ARROW)) {
     yCobra -= velocidadeMovimentacao;
   }
 if (keyIsDown(DOWN_ARROW)) {
     yCobra += velocidadeMovimentacao;
   }
 }
Primeira movimentação da cobrinha
Primeira movimentação da nossa cobra. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Perfeito, mas não é bem assim que funciona o game… precisamos que nossa cobrinha se movimente continuamente e seja direcionada por movimentos do teclado, então precisamos modificar esse código para algo mais ou menos assim:

let xCobra = 50;
let yCobra = 40;
let wCobra = 10;
let hCobra = 10;
let direcao = "right";
let velocidadeMovimentacao = 1;

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(51);
  desenhaCobrinha();
  controleMovimentacao();
}

function desenhaCobrinha() {
  rect(xCobra, yCobra, wCobra, hCobra);
  
}

function controleCobra() {
  if (keyIsDown(LEFT_ARROW)) {
    return "left";
  }

  if (keyIsDown(RIGHT_ARROW)) {
    return "right";
  }

  if (keyIsDown(UP_ARROW)) {
    return "up";
  }

  if (keyIsDown(DOWN_ARROW)) {
    return "down";
  }
}

function controleMovimentacao() {
  if (controleCobra()) {
    direcao = controleCobra();
  }

  if (direcao == "right") {
    xCobra += velocidadeMovimentacao;
  }
  if (direcao == "up") {
    yCobra -= velocidadeMovimentacao;
  }
  if (direcao == "left") {
    xCobra -= velocidadeMovimentacao;
  }
  if (direcao == "down") {
    yCobra += velocidadeMovimentacao;
  }
}
primeira movimentação continua da cobrinha
Movimentação contínua da cobrinha. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Agora que nossa movimentação contínua já existe podemos adicionar paredes nas bordas e adicionar também colisão. Assim, quando nossa cobrinha bater em uma parede a cobrinha reaparece no centro da tela como se o jogo tivesse sido reiniciado:

Adicionando colisão com a parede. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Mas, para isso, precisamos instalar uma biblioteca em nosso projeto, essa biblioteca é o Collision2D. Assim, vamos instalar esse pacote no VScode usando o atalho CTRL + SHIFT + P e instalando o pacote.

Como instalar pacotes do P5js no VScode. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Bom, depois de instalar nossa dependência vamos criar nosso código para mostrar as paredes e realizar a colisão:

let canvaW = 400;
let canvaH = 400;

// controles da cobra
let xCobra = 50;
let yCobra = 40;
let wCobra = 10;
let hCobra = 10;
let partes = 1;

let rabo = [];

let velocidadeMovimentacao = 5;
let direcao = "right";

// comida

posicaoXComida = randomIntFromInterval(11, canvaW - 10);
posicaoYComida = randomIntFromInterval(11, canvaW - 10);

let colidiu = false;
let comeu = false;

// paredes
// esquerda|dir
let wParED = 10;
let hParED = 400;
let posXParE = 0;
let posYParE = 0;
let posXParD = 390;
let posYParD = 0;

// cima|baixo
let wParCB = 400;
let hParCB = 10;
let posXParC = 0;
let posYParC = 0;
let posXParB = 0;
let posYParB = 390;

function setup() {
  createCanvas(canvaW, canvaH);
  frameRate(10);
}

function draw() {
  background(0);
  desenhaCobrinha();
  desenhaParedes();
  controleMovimentacao();
  colisaoNasParedes();
}

function desenhaCobrinha() {
  rect(xCobra, yCobra, wCobra, hCobra);
  if (rabo.length > 0) {
    for (var i = 0; i < rabo.length; i++) {
      rect(rabo[i][0], rabo[i][1], wCobra, hCobra);
    }
  }
}

function desenhaParedes() {
  rect(posXParE, posYParE, wParED, hParED);
  rect(posXParD, posYParD, wParED, hParED);
  rect(posXParC, posYParC, wParCB, hParCB);
  rect(posXParB, posYParB, wParCB, hParCB);
}

function controleCobra() {
  if (keyIsDown(LEFT_ARROW)) {
    return "left";
  }

  if (keyIsDown(RIGHT_ARROW)) {
    return "right";
  }

  if (keyIsDown(UP_ARROW)) {
    return "up";
  }

  if (keyIsDown(DOWN_ARROW)) {
    return "down";
  }
}

function controleMovimentacao() {
  if (controleCobra()) {
    direcao = controleCobra();
  }

  if (direcao == "right") {
    xCobra += velocidadeMovimentacao;
  }
  if (direcao == "up") {
    yCobra -= velocidadeMovimentacao;
  }
  if (direcao == "left") {
    xCobra -= velocidadeMovimentacao;
  }
  if (direcao == "down") {
    yCobra += velocidadeMovimentacao;
  }
}

function colisaoNasParedes() {
  var colisaoDireita = collideRectRect( xCobra, yCobra, wCobra, hCobra, posXParD, posYParD, wParED, hParED );
   var colisaoEquerda = collideRectRect( xCobra, yCobra, wCobra, hCobra, posXParE, posYParE, wParED, hParED   );    
   var colisaoCima = collideRectRect( xCobra, yCobra, wCobra, hCobra, posXParC, posYParC, wParCB, hParCB   );    
   var colisaoBaixo = collideRectRect( xCobra, yCobra, wCobra, hCobra, posXParB, posYParB, wParCB, hParCB   );

  if ( colisaoCima == true || colisaoBaixo == true || colisaoDireita == true || colisaoEquerda == true) {
    xCobra = 200;
    yCobra = 200;
    rabo = [];
    partes = 0;
  }
}

// funções auxiliares
function randomIntFromInterval(min, max) {
  // min and max included
  return Math.floor(Math.random() * (max - min + 1) + min);
}

Por fim, agora vamos adicionar o rabinho da nossa cobrinha… para isso precisamos definir um vetor que armazena historicamente quantos “pedaços” nossa cobrinha possui. Então imagine o seguinte, nossa cobrinha está na posição [4,4]:

posicao inicial da cobrinha (representação)
Representação da posição inicial da cobrinha. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

e quando ela se move ela deverá ter um “rabinho” de 2 pedaços:

movimentação cobrinha representação
Aqui a cabeça da nossa cobrinha está em amarelo escuro.

Perceba que a nossa cobrinha passa por [6,4], [6,5] e [6,6]. Então é como se os pedaços depois da cabeça da nossa cobrinha fossem apenas rastros que ela irá deixar. Então para codificar isso vamos criar um vetor:

let rabo = [];

e também uma variável mostrando quantos “pedaços” minha cobra terá:

let partes = 1;

Cada vez que a cobrinha come, um pedaço é adicionado a nossa cobra, portanto precisamos modificar a nossa função de exibição da cobrinha e também adicionar uma função que registra historicamente por onde nossa cobrinha anda passando. Por fim, temos algo assim:

Demonstração do resultado final do jogo da cobrinha.
Demonstração final do funcionamento do nosso jogo. Fonte: Autoria Própria – Licença (CC-BY-SA 4.0)

Para isso codificamos:

let canvaW = 400;
let canvaH = 400;

// controles da cobra
let xCobra = 50;
let yCobra = 40;
let wCobra = 10;
let hCobra = 10;
let partes = 1;

let rabo = [];

let velocidadeMovimentacao = 5;
let direcao = "right";

// comida

posicaoXComida = randomIntFromInterval(11, canvaW - 10);
posicaoYComida = randomIntFromInterval(11, canvaW - 10);

let colidiu = false;
let comeu = false;

// paredes
// esquerda|dir
let wParED = 10;
let hParED = 400;
let posXParE = 0;
let posYParE = 0;
let posXParD = 390;
let posYParD = 0;

// cima|baixo
let wParCB = 400;
let hParCB = 10;
let posXParC = 0;
let posYParC = 0;
let posXParB = 0;
let posYParB = 390;

function setup() {
  createCanvas(canvaW, canvaH);
  frameRate(10);
}

function draw() {
  background(0);
  desenhaCobrinha();
  desenhaParedes();
  desenhaComida();
  controleMovimentacao();
  colisaoNasParedes();
  comer();
  pegarPosicaoAtual();
}

function pegarPosicaoAtual() {
  
  rabo.push([xCobra, yCobra]);
  if (rabo.length > partes) {
    rabo.shift();
  }
}

function desenhaComida() {
  rect(posicaoXComida, posicaoYComida, 10, 10);
}

function desenhaCobrinha() {
  rect(xCobra, yCobra, wCobra, hCobra);
  if (rabo.length > 0) {
    for (var i = 0; i < rabo.length; i++) {
      rect(rabo[i][0], rabo[i][1], wCobra, hCobra);
    }
  }
}

function desenhaParedes() {
  rect(posXParE, posYParE, wParED, hParED);
  rect(posXParD, posYParD, wParED, hParED);
  rect(posXParC, posYParC, wParCB, hParCB);
  rect(posXParB, posYParB, wParCB, hParCB);
}

function controleCobra() {
  if (keyIsDown(LEFT_ARROW)) {
    return "left";
  }

  if (keyIsDown(RIGHT_ARROW)) {
    return "right";
  }

  if (keyIsDown(UP_ARROW)) {
    return "up";
  }

  if (keyIsDown(DOWN_ARROW)) {
    return "down";
  }
}

function controleMovimentacao() {
  if (controleCobra()) {
    direcao = controleCobra();
  }

  if (direcao == "right") {
    xCobra += velocidadeMovimentacao;
  }
  if (direcao == "up") {
    yCobra -= velocidadeMovimentacao;
  }
  if (direcao == "left") {
    xCobra -= velocidadeMovimentacao;
  }
  if (direcao == "down") {
    yCobra += velocidadeMovimentacao;
  }
}

function colisaoNasParedes() {
  var colisaoDireita = collideRectRect(xCobra, yCobra, wCobra, hCobra, posXParD, posYParD, wParED, hParED);    
  var colisaoEquerda = collideRectRect( xCobra, yCobra, wCobra, hCobra, posXParE, posYParE, wParED, hParED);    
  var colisaoCima = collideRectRect( xCobra, yCobra, wCobra, hCobra, posXParC, posYParC, wParCB, hParCB);    
  var colisaoBaixo = collideRectRect( xCobra, yCobra, wCobra, hCobra, posXParB, posYParB, wParCB, hParCB);

  if ( colisaoCima == true || colisaoBaixo == true || colisaoDireita == true || colisaoEquerda == true) {
    xCobra = 200;
    yCobra = 200;
    rabo = [];
    partes = 0;
  }
}

function colisaoComida() {
  var colisaoComida = collideRectRect( posicaoXComida, posicaoYComida, 10, 10, xCobra, yCobra, wCobra, hCobra );
  return colisaoComida;
}

function comer() {
  if (colisaoComida()) {
    posicaoXComida = randomIntFromInterval(11, canvaW - 10);
    posicaoYComida = randomIntFromInterval(11, canvaW - 10);
    partes += 1
  }
}

// funções auxiliares
function randomIntFromInterval(min, max) {
  // min and max included
  return Math.floor(Math.random() * (max - min + 1) + min);
}

Conclusão

E ai, gostou do jogo da cobrinha?

Posso dizer que talvez essa não seja a forma mais elegante de codificar esse game, porém, o exemplo mostrado aqui é funcional (não podemos negar). Você poderia melhorar esse código, por exemplo, usando classes e objetos para modularizar o desenvolvimento da nossa cobrinha.

Caso você queira acessar nosso repositório:

Veja nosso Github

Vinicius dos Santos

Apenas um apaixonado por Ciência da Computação e a forma com que ela pode transformar vidas!

Deixe um comentário

9 − seis =