quinta-feira, 18 de julho de 2013

Criando forma ao nosso tabuleiro

Boa noite!
No post anterior, demos início ao nosso jogo de Xadrez.
Hoje vamos dar forma ao nosso tabuleiro. Mas, para isso, precisamos modificar e incluir novas coisas em nosso projeto.
Nós precisamos de uma maneira de representar o modelo de nosso tabuleiro. Aqui não estamos falando do tabuleiro em si, aquele que você vê na tabela, mas estamos falando do que um tabuleiro contém. Então, vamos criar o código que representará isso:
public class TabuleiroModel {
 private PecaModel pecas[][];

 public TabuleiroModel() {
  pecas = new PecaModel[8][8];
 }

 public void montaTabuleiro() {
 }

 public PecaModel[][] getPecas() {
  return pecas;
 }

 public void setPecas(PecaModel[][] pecas) {
  this.pecas = pecas;
 }
 
 public PecaModel getPeca(int linha, int coluna) {
  return pecas[linha][coluna];
 }
}

Veja que aqui não temos nenhum elemento de interface gráfica. Esta classe apenas representa o modelo do tabuleiro. Mas e o que é aquele PecaModel? Bom, precisamos de Peças em nosso jogo, correto? Então, assim como o tabuleiro, precisamos de uma classe que representa cada peça do jogo. Vamos ao código, para que a classe TabuleiroModel faça mais sentido:
public abstract class PecaModel {
 private boolean selecionada;
 private String cor;
 private int linha;
 private int coluna;

 public int getLinha() {
  return linha;
 }

 public void setLinha(int linha) {
  this.linha = linha;
 }

 public int getColuna() {
  return coluna;
 }

 public void setColuna(int coluna) {
  this.coluna = coluna;
 }

 public PecaModel(String cor, int linha, int coluna) {
  this.cor = cor;
  this.linha = linha;
  this.coluna = coluna;
 }

 public boolean isSelecionada() {
  return selecionada;
 }

 public void setSelecionada(boolean selecionada) {
  this.selecionada = selecionada;
 }

 public String getCor() {
  return cor;
 }

 public void setCor(String cor) {
  this.cor = cor;
 }
}

Bom, a classe acima representa uma peça. Não sabemos que tipo de peça é (torre, cavalo, etc), por isso ela é uma classe abstrata. Não faz sentido fazer Peca p = new Peca(). Que cor? Que tipo de peça? Por esse motivo ela é abstrata. Se observamos a classe TabuleiroModel, vamos encontrar uma matriz de PecaModel, representado pelo atributo pecas. Ele representa uma matriz de 8x8, onde cada posição dessa armazenará um PecaModel. E faz muito sentido isso, porque dizemos "um tabuleiro tem várias peças". O método que nos auxiliará a "pegar" determinada peça de nosso tabuleiro é o getPeca, onde o mesmo retorna um PecaModel, recebendo a linha e a coluna que a suposta peça se encontra (mais para frente vamos entender o porque de "suposta").

A princípio, nosso modelo está pronto. Temos nosso tabuleiro e nossa peça representados corretamente. Agora é hora de partirmos para a interface gráfica do nosso tabuleiro! Precisamos fazer alguns ajustes antes de termos nosso tabuleiro na tela.No post anterior, nós já criamos a classe que representa o tabuleiro graficamente. O que precisamos fazer agora é representar a Peca graficamente. Vamos escrever isso?
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Peca extends JLabel {
 private PecaModel pecaModel;

 public PecaModel getPecaModel() {
  return pecaModel;
 }

 public void setPecaModel(PecaModel pecaModel) {
  this.pecaModel = pecaModel;
 }

 public Peca(PecaModel peca) {
  this.pecaModel = peca;
 }
}

A classe Peca faz um extends em JLabel, para que possamos plotá-lo no tabuleiro. É um label normal, não há nada de diferente aqui. Além disso, observe que temos um atributo do tipo PecaModel (que é o modelo). O que é interessante é que não estamos colocando nossa regra de negócio na tela, o que é um bom começo, visto que, se lá na frente formos precisar usar uma interface Web, não teríamos problemas.

Calma, já estamos quase lá...

Lembra da classe Celula do post anterior? Vamos melhorá-la para se adequar a nossa nova realidade:
import javax.swing.JPanel;

public class Celula extends JPanel {
 private int linha;
 private int coluna;
 private Peca peca;
 
 public Celula(Peca peca) {
  this(peca.getPecaModel().getLinha(),peca.getPecaModel().getColuna());
  this.peca = peca;
  this.add(peca);
 }
 
 public Celula(int linha, int coluna) {
  this.linha = linha;
  this.coluna = coluna;
 }

 public int getLinha() {
  return linha;
 }

 public void setLinha(int linha) {
  this.linha = linha;
 }

 public int getColuna() {
  return coluna;
 }

 public void setColuna(int coluna) {
  this.coluna = coluna;
 }

 public Peca getPeca() {
  return peca;
 }

 public void setPeca(Peca peca) {
  this.peca = peca;
 }

}
Vamos com calma. Fiz questão de destacar as partes mais importantes dessa classe. Primeiramente, vemos um atributo do tipo Peca. Mas dessa vez NÃO é nosso modelo, é a Peca representada graficamente... pois quem tem o modelo da peca (PecaModel) é a própria classe Peca! Observe também os dois construtores da classe Celula, um recebendo uma Peca e outro recebendo uma linha e uma coluna... mas agora não é hora de explicar o porque disso. Apenas atente-se ao fato de que quando o construtor que recebe uma Peca é invocado, a célula adiciona a Peca a ela mesma, como se estivéssemos dizendo "Ok, coloque uma peça nessa célula aqui".
Bom, chegou a hora de montar o nosso tabuleiro (pelo menos fazer ele aparecer na tela!).
import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Tabuleiro extends JPanel {
 public void montaTabuleiro() {
  this.setLayout(new GridLayout(8, 8));
  this.removeAll();
  for (int i = 0; i < 8; i++) {
   for (int j = 0; j < 8; j++) {
    Celula celula;
    celula = new Celula(i, j);
    if ((i + j) % 2 == 0) {
     celula.setBackground(Color.WHITE);
    } else {
     celula.setBackground(Color.BLACK);
    }
    this.add(celula);
   }
  }
  this.revalidate();
 }
}
Ué, e cade todos aquelas classes que sofremos para codificar?
Calma... estamos fazendo a base para o próximo POST, se não ia perder toda a graça, não é mesmo? :)
Bom, vamos explicar esse código:
A classe Tabuleiro continua sendo um JPanel, como no post anterior. Observe que fizemos um duplo laço (para simular a varredura em uma matriz mesmo), sendo o "i" a linha e o "j" a coluna. Dentro do laço mais interno, veja que instanciamos um objeto Celula, passando como parâmetros quem? A linha e a coluna! Ou seja, agora sabemos exatamente qual posição a célula ocupará no tabuleiro. Para saber se ela deve ser preta ou branca, fazemos a seguinte lógica: se o resto da divisão da soma entre i e j for igual a 0, então pintamos de branco, se não pintamos de preto. Após termos pintado a célula, precisamos adicioná-la no painel, através do método add(celula).
O final deverá se parecer com isso:

Ufa! Quanto trabalho por hoje! No próximo POST, vamos utilizar toda a estrutura que criamos anteriormente, para começarmos a colocar as nossas peças no tabuleiro! Uma prévia do que vem pela frente:
  Nosso tabuleiro conterá peças! :) Então, até a próxima!

PS: Achei esse link para formatar códigos muito bom! Parabéns ao criador.





Nenhum comentário:

Postar um comentário