Clássico Jogo da Minhoca (Snake) em Java

    O "Snake", conhecido popularmente como jogo da cobrinha, é um clássico em vários dispositivos. Muito difundido no antigo e conhecido celular "tijolo" da Nokia. Neste artigo vamos fazer uma releitura deste saudoso jogo na linguagem Java. Basicamente utilizaremos 2 classes java e 7 imagens, do tipo png e jpg.

Vamos ao código, segue abaixo a classe Principal.java na integra, logo depois alguns comentários para ajudar o entendimento: 

import java.awt.Color;

import javax.swing.JFrame;


public class Principal {

public static void main(String[] args) {

JFrame obj = new JFrame();

Gameplay gameplay = new Gameplay();

obj.setBounds(10, 10, 905, 700);

obj.setBackground(Color.DARK_GRAY);

obj.setResizable(false);

obj.setVisible(true);

obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

obj.add(gameplay);

}

}


A classe Principal.java cria o JFrame para acomodar o jogo em si e então cria um objeto do tipo Gameplay adicionando-o ao JFrame tomando-o como um todo. O método setBounds funciona da seguinte maneira: 

setBounds(int x, int y, int width, int height)

onde o "x" é a coordenada do eixo x na tela, desta forma o "y" corresponde ao eixo y, os parâmetros width e height são respectivamente largura e altura da tela, desta forma dimensionamos e posicionamos a janela na tela do usuário;

Agora segue a classe Gameplay.java:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Gameplay extends JPanel implements KeyListener, ActionListener{
private ImageIcon imagemTitulo;
private int[] cobraX = new int[750];
private int[] cobraY = new int[750];
private boolean esquerda = false;
private boolean direita = false;
private boolean cima = false;
private boolean baixo = false;
private ImageIcon direitaI;
private ImageIcon cimaI;
private ImageIcon baixoI;
private ImageIcon esquerdaI;
private Timer tempo;
private int delay = 100;
private ImageIcon corpo;
private int tamanhoCobra = 3;
private int movimentos = 0;
private int [] inimigoX = {25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 525, 550, 575, 600, 625, 650, 675, 700, 725, 750, 775, 800, 825, 850};
private int [] inimigoY = {75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 525, 550, 575, 600, 625};
private ImageIcon inimigoI;
private Random aleatorio = new Random();
private int xpos = aleatorio.nextInt(34);
private int ypos = aleatorio.nextInt(23);
private int pontos = 0;
public Gameplay() {
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
tempo = new Timer(delay, this);
tempo.start();
}
public void paint(Graphics g) {
if(movimentos == 0) {
cobraX[2] = 50;
cobraX[1] = 75;
cobraX[0] = 100;
cobraY[2] = 100;
cobraY[1] = 100;
cobraY[0] = 100;
}
// borda do título
g.setColor(Color.white);
g.drawRect(24, 10, 851, 55);
//titulo
imagemTitulo = new ImageIcon("titulo.jpg");
imagemTitulo.paintIcon(this, g, 25, 11);
//borda do jogo
g.setColor(Color.WHITE);
g.drawRect(24, 74, 851, 577);
// fundo do jogo
g.setColor(Color.black);
g.fillRect(25, 75, 850, 575);
// pontos
g.setColor(Color.white);
g.setFont(new Font("arial", Font.PLAIN, 14));
g.drawString("Pontos: " + pontos, 780, 30);
// tamanho
g.setColor(Color.white);
g.setFont(new Font("arial", Font.PLAIN, 14));
g.drawString("Tamanho: " + tamanhoCobra, 780, 50);
direitaI = new ImageIcon("direita.png");
direitaI.paintIcon(this, g, cobraX[0], cobraY[0]);
for(int n = 0; n < tamanhoCobra; n++) {
if((n == 0) && (direita)) {
direitaI = new ImageIcon("direita.png");
direitaI.paintIcon(this, g, cobraX[n], cobraY[n]);
}
if((n == 0) && (esquerda)) {
esquerdaI = new ImageIcon("esquerda.png");
esquerdaI.paintIcon(this, g, cobraX[n], cobraY[n]);
}
if((n == 0) && (baixo)) {
baixoI = new ImageIcon("baixo.png");
baixoI.paintIcon(this, g, cobraX[n], cobraY[n]);
}
if((n == 0) && (cima)) {
cimaI = new ImageIcon("cima.png");
cimaI.paintIcon(this, g, cobraX[n], cobraY[n]);
}
if (n != 0) {
corpo = new ImageIcon("corpo.png");
corpo.paintIcon(this, g, cobraX[n], cobraY[n]);
}
}
inimigoI = new ImageIcon("inimigo.png");
if((inimigoX[xpos] == cobraX[0]) && (inimigoY[ypos] == cobraY[0])) {
pontos++;
tamanhoCobra++;
xpos = aleatorio.nextInt(34);
ypos = aleatorio.nextInt(23);
}
inimigoI.paintIcon(this, g, inimigoX[xpos], inimigoY[ypos]);
for(int b = 1; b < tamanhoCobra; b++) {
if((cobraX[b] == cobraX[0]) && (cobraY[b] == cobraY[0])) {
direita = false;
esquerda = false;
cima = false;
baixo = false;
g.setColor(Color.white);
g.setFont(new Font("arial", Font.BOLD, 50));
g.drawString("Fim de Jogo", 300, 300);
g.setFont(new Font("arial", Font.BOLD, 20));
g.drawString("Pressione espaço para começar", 350, 340);
}
}
g.dispose();
}

@Override
public void actionPerformed(ActionEvent e) {
tempo.start();
if(direita) {
for(int r = tamanhoCobra - 1; r >= 0; r--) {
cobraY[r + 1] = cobraY[r]; 
}
for(int r = tamanhoCobra; r >= 0; r--) {
if(r == 0) {
cobraX[r] = cobraX[r] + 25;
} else {
cobraX[r] = cobraX[r - 1];
}
if(cobraX[r] > 850) {
cobraX[r] = 25;
}
}
repaint();
}
if(esquerda) {
for(int r = tamanhoCobra - 1; r >= 0; r--) {
cobraY[r + 1] = cobraY[r]; 
}
for(int r = tamanhoCobra; r >= 0; r--) {
if(r == 0) {
cobraX[r] = cobraX[r] - 25;
} else {
cobraX[r] = cobraX[r - 1];
}
if(cobraX[r] < 25) {
cobraX[r] = 850;
}
}
repaint();
}
if(baixo) {
for(int r = tamanhoCobra - 1; r >= 0; r--) {
cobraX[r + 1] = cobraX[r]; 
}
for(int r = tamanhoCobra; r >= 0; r--) {
if(r == 0) {
cobraY[r] = cobraY[r] + 25;
} else {
cobraY[r] = cobraY[r - 1];
}
if(cobraY[r] > 625) {
cobraY[r] = 75;
}
}
repaint();
}
if(cima) {
for(int r = tamanhoCobra - 1; r >= 0; r--) {
cobraX[r + 1] = cobraX[r]; 
}
for(int r = tamanhoCobra; r >= 0; r--) {
if(r == 0) {
cobraY[r] = cobraY[r] - 25;
} else {
cobraY[r] = cobraY[r - 1];
}
if(cobraY[r] < 75) {
cobraY[r] = 625;
}
}
repaint();
}
}

@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}

@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
movimentos = 0;
pontos = 0;
tamanhoCobra = 3;
repaint();
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
movimentos++;
direita = true;
if(!esquerda) {
direita = true;
} else {
direita = false;
esquerda = true;
}
cima = false;
baixo = false;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
movimentos++;
esquerda = true;
if(!direita) {
esquerda = true;
} else {
direita = true;
esquerda = false;
}
cima = false;
baixo = false;
}
if(e.getKeyCode() == KeyEvent.VK_UP) {
movimentos++;
cima = true;
if(!baixo) {
cima = true;
} else {
baixo = true;
cima = false;
}
esquerda = false;
direita = false;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
movimentos++;
baixo = true;
if(!cima) {
baixo = true;
} else {
baixo = false;
cima = true;
}
esquerda = false;
direita = false;
}
}

@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}

Agora os pontos relevantes desta classe, esta classe extende de JPanel para ser abrigada pela JFrame principal e implementa as interfaces "KeyListener" e "ActionListener", estas implementações nos ajuda na captura das teclas clicadas pelo usuário e todo o "desenho" (renderização) do jogo utilizamos a biblioteca java.awt.Graphics, que serve exatamente para desenhar formas, pontos e etc. em janelas java.
    As variáveis do tipo ImageIcon correspondem as imagens utilizadas no programa/jogo, as imagens devem ser colocadas na mesma pasta em que foram salva as 2 classes do programa.
    Como o personagem principal, logo depois de iniciado o jogo, tem movimento continuo infinito até que ele bata/encoste nele mesmo, pensando desta maneira temos as 4 direções do tipo booleana (esquerda, direita, cima e baixo) que complementam este raciocínio pois enquanto a variável for true o personagem ficará andando naquela direção. A variável "tamanhoCobra" controla o tamanho do personagem conforme é acrescentado tamanho batendo/encostando/tocando em "inimigoI" que em sua vez precisa aparecer em lugares aleatórios pra envolver certa dificuldade/desafio ao jogador, assim as variáveis inimigoX e inimigoY são arrays com pontos específicos de coordenadas na tela e as variáveis xpos e ypos é que proporcionam a aleatoriedade ao "inimigo".
    Implementando KeyListener e ActionListener somos forçados a implementar os seguintes métodos:
actionPerformed(ActionEvent e)
keyTyped(KeyEvent e)
keyPressed(KeyEvent e)
keyReleased(KeyEvent e)

    Para este projeto não tratamos os métodos keyTyped e keyReleased, pois o keyPressed já resolve nosso problema em capturar a tecla pressionada no teclado do usuário, por isso que temos um "if" que trata cada tecla pressionada enquanto que o actionPerformed cuida para que o personagem vá para o lado pretendido pelo jogador.
    O Método paint que utiliza da biblioteca Graphics, é quem cuida de desenhar os objetos em tela, é nele que damos cores e posições ao elenco do jogo.
    Finalizando sequem as imagens utilizadas neste projeto, espero que tenham gostado e grande abraço!!!









Comentários

  1. aooooooooooooooooooo tio fera so eu matheus

    ResponderExcluir
  2. Caso você realizou os procedimentos todos certos e as imagens não estejam aparecendo acrescente o getClass().getResource dentro do ImageIcon, exemplo: imagemTitulo = new ImageIcon(getClass().getResource("/snake/titulo.jpg"));

    ResponderExcluir

Postar um comentário

Postagens mais visitadas deste blog

Ion-button e ion-card

Ion-badge e ion-breadcrumbs

O AWT: Ninguém tá usando o AWT?