BatalhaNaval GUI

101 respostas
actionlistenerjava
IghorSantiago

Boa noite,
estou fazendo um jogo de Batalha Naval com interface gráfica.
O tabuleiro está montado e os navios da IA estão posicionados aleatoriamente, mas não consigo posicionar os navios do player com o mouse.
Eu fiz um antes que usava JOptionPane para pegar a linha e a coluna que o player queria para posicionar o navio, mas assim fica muito ruim.

Quando boto no método pra pegar a linha e a coluna do botão selecionado, ele da um nullPointerException.

Consequentemente, o mesmo acontece no método para atirar…

Alguém pode me ajudar?

101 Respostas

TerraSkilll

Como não temos seu código aqui, fica extremamente difícil saber o motivo do nullPointerException. Se ele não for muito extenso, poderia postá-lo?

Ou ao menos explique qual era a sua ideia de como fazer isso, para que possamos sugerir algo em cima do seu plano.

Particularmente, eu não usaria botões para isso, mas um JPanel com desenho personalizado, usando Java2D. Para saber em qual parte o usuário clicou, basta usar um mouselistener, pegando as coordenadas X e Y do evento mousepressed, por exemplo. O tabuleiro poderia ser armazenado internamente no programa, em uma matriz, e o desenho seria feito a partir de imagens representando os pedaços das embarcações.

Abraço.

IghorSantiago

Só conseguirei postar o código amanhã, mas fiz mais ou menos do jeito que você falou.
“Botão” foi só um mode de falar. Fiz uma matriz de “botões” e todos com evento de mouselistener. Porém, quando eu tento pegar as coordenadas, ele dá NPE, porque não espera o clique.
Quando eu clico em “Novo Jogo”, ele posiciona os navios da IA e entra no loop pra posicionar os navios do player, mas, nesse momento, X e Y ainda estão vazios, ai ele da NPE.
Não sei se expliquei muito bem. Caso tenha ficado alguma dúvida, amanhã eu posto uma parte do código, já que completo não tem como.

Obrigado pela força!

Abraço.

staroski

Você está tentando acessar membros de uma variável que não foi inicializada

IghorSantiago

Bom dia…
Todas as variáveis estão inicializadas.
Quando li seu post, pensei: “Será que fiz isso?”
Mas fui verificar e vi que estão inicializadas.

A linha selecionada:
Botao btn = new Botao()
selecionado //clique do mouse na classe Botao
getLinha() //auto explicativo

Mike

Bom dia, em cima da linha 38, faz assim:

if(btn == null){
System.out.prinln("btn nulo");
}
if(btn.selecionado == null){
System.out.prinln("selecionado nulo");
}

Ai você tira a suas próprias conclusoes.

PS: Se Btn foi inicializado, então diria que selecionado ta nulo então

IghorSantiago

Bom dia Mike, obrigado pela resposta.
Botei os if’s e ele fala que o “selecionado” está null. Como ele é criado dentro da classe Botao, realmente não inicializei.

Quando coloco:
Botao selecionado = new Botao();
Ele gera StackOverflowError

Tentei agora sem o selecionado:
btn.getLinha();
Mas aí ele pega sempre a posição [0][0] do tabuleiro e entra em loop infinito.

O JOptionPane foi só um teste para ver se os “botões” estavam funcionando.

IghorSantiago

Alguém me ajuda?
Qualquer coisa posto outras partes do código aqui.

D

O problema não parece estar aí, essa exceção geralmente acontece quando há recursão.

Por que pega sempre a posição [0][0]?

IghorSantiago

Boa tarde diego12,
obrigado pela resposta.

Porque o programa não “espera” o clique do mouse, aí ele vem com os valores que eu inicializei as variáveis ‘linha’ e ‘coluna’.
Quando entra no método ‘posicionaNavio()’, ele já entra direto no loop e não deixa com que eu selecione um ‘botão’ onde quero posicionar o navio.
Essa é a minha dúvida, como fazer para ele ‘esperar’ o clique.

public void posicionaPlayer() {

		int navios = 1, orientacao = 0, linha = 0, coluna = 0;
		
		while(navios <= 5) {
			
			navio = navio.constroiNavio(navios);
			
			JOptionPane.showMessageDialog(
					null, "Posicione o " + navio.getNome() + "."
						+ "\nEsse navio ocupa " + navio.getTamanho() + " espaços."
						+ "\nEscolha o primeiro espaço que ele irá ocupar...");
		
			Object[] opcoes = {"Horizontal", "Vertical"};
			
			orientacao = JOptionPane.showOptionDialog(null,
								"Escolha a orientação do navio",
								"Escolha",
								JOptionPane.YES_NO_CANCEL_OPTION,
								JOptionPane.QUESTION_MESSAGE,
								null,
								opcoes,
								opcoes[1]);
				
			linha = btn.getLinha();
			coluna = btn.getColuna();
			
			if(navio.getTamanho() != 0) {

				if(orientacao < 2) {
					
					if(linha < 10) {
					
						if(coluna < 10) {
							
							if(navio.posicionaNavio("C", orientacao, linha, coluna, navio, tabuleiroPlayer)) {

								navios++;
							}
						}
						else
							posicionaPlayer();
					}
					else
						posicionaPlayer();
				}
				else
					posicionaPlayer();
			}
			else
				posicionaPlayer();
		}
		
		navio.posicionaNavio("P", orientacao, linha, coluna, navio, tabuleiroPlayer);
	}

Coloquei pra pegar a orientação (horizontal ou vertical) pelo JOptionPane pra ver se facilitava, mas a única coisa que faz é colocar o primeiro navio, na posição 0,0.

Dei uma lida no link que você botou. Se eu entendi bem, tá dando o StackOverFlowError pq eu instanciei o ‘selecionado’ dentro da classe Botão?

Ofidomundo

coloca algum tipo de wait();

IghorSantiago

Fala Ofidomundo,

“Ofidomundo:

coloca algum tipo de wait();

Já procurei métodos parecidos mas não achei. Sabe de algum?

Ofidomundo

Pelo que me lembro o JOP retorna um valor, põe num while vaziu que resolve eu acho

IghorSantiago

Eu tenho uma BatalhaNaval pronta que faz tudo por JOptionPane.
Eu digito linha e coluna tanto pra colocar os navios quanto para atirar, mas não é o que eu quero.
Se eu não me engano, JOptionPane não pega click.

Ofidomundo

Sobe pro Git que eu olho amanhã às 8 pdc? Sai da empresa agr

TerraSkilll

De onde é chamado esse posicionaPlayer()? É dentro de algum evento de clique? Não acho que é uma boa ideia você colocar um while dentro de um evento da interface (mouseClick, etc).

O que é essa classe Botao? Ela deriva de algum componente visual (ex: Jbutton) ou é uma classe mais simples?

Abraço.

D

Não, o problema seria a recursão, quando chama um mesmo método infinitas vezes, exemplo:

void posicionaPlayer(){
  posicionaPlayer();
}

Ou seja, provavelmente esta caindo no “else posicionaPlayer()” até acontecer esse erro.

Sugestão, remova todos os “else posicionaPlayer()”, coloque um System.out.print para cada if verificando se está certo, como exemplo abaixo:

System.out.println("Coluna: " + coluna);
if(coluna < 10) {
	boolean posicionouNavioC = navio.posicionaNavio("C", orientacao, linha, coluna, navio, tabuleiroPlayer);
	System.out.println("Posicionou navio C? " + posicionouNavioC);
	if(posicionouNavioC) {
		navios++;
	}
}
IghorSantiago

Fala TerraSkilll, valeu pela atenção…

A classe Botao que eu criei estende JLabel, foi a forma que eu encontrei pra fazer o tabuleiro.
O posicionaPlayer() é chamado que eu clico em “Novo Jogo” no menu.
O posicionaPlayer() ta dentro da classe player, só a chamada do método tá dentro do evento.

IghorSantiago

Fala Diego, obrigado mais uma vez.
Amanhã eu vou tirar os else’s para ver, mas acho que só resolveria o problema do StackOverFlow. Não resolveria o problema do click. Certo?
Mas vou colocar os Sysout pra ver até onde está indo.

Ofidomundo

@IghorSantiago se quiser colocar o codigo em algum repositório para eu te ajudar fique a vontade

TerraSkilll

Bom, tentar ajustar o seu código pode ser complicado, mas pode ver se o Ofidomundo te ajuda, se você enviar.

O que posso fazer é sugerir uma alternativa, de como eu faria isso.

O tabuleiro eu faria criando uma classe que estendesse JPanel, sobrescrevendo ao menos o método paintComponent pra fazer o desenho do tabuleiro, ao invés de JLabels. Com dois loops for (um pra linhas e outro pra colunas), é possível desenhar um tabuleiro facilmente.

Esse JPanel poderia receber o evento mouseCliked ou mousePressed, pra saber que posição foi clicada e o que fazer: inserir o um navio, por exemplo. Internamente, esse tabuleiro pode ser armazenado numa matriz de inteiros por exemplo, em que 1 indica posição ocupada e zero uma posição livre (água).

Exemplo:

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;

public class ExemploTabuleiro extends JFrame{
    public static int TAMANHO = 20;

    private int[][] matrizTabuleiro = new int[10][10];

    public ExemploTabuleiro(){
        super("Exemplo");
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        setLayout(new BorderLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setPreferredSize(new Dimension(500, 500));
        setSize(getPreferredSize());

        PainelTabuleiro tb = new PainelTabuleiro();

        getContentPane().add(tb, BorderLayout.CENTER);

        for (int i = 0; i < matrizTabuleiro.length; i++){
            for (int j = 0; j < matrizTabuleiro[i].length; j++){
                matrizTabuleiro[i][j] = 0;
            }
        }
    }

    public static void main(String[] args){
        java.awt.EventQueue.invokeLater(() -> {
            ExemploTabuleiro e = new ExemploTabuleiro();
            e.setVisible(true);
        });
    }

    class PainelTabuleiro extends JPanel{

        public PainelTabuleiro(){
            // adiciona o mouselistener
            addMouseListener(new MouseAdapter() { 
                public void mouseClicked(MouseEvent me) { 
                    tratarClique(me.getX(), me.getY()); 
                } 
            }); 
        }

        private void tratarClique(int x, int y){
            if (x < 100 || y < 100){
                return;
            }

            // verifica se o clique foi na área de desenho
            int cx = (x - 100) / ExemploTabuleiro.TAMANHO;
            int cy = (y - 100) / ExemploTabuleiro.TAMANHO;

            // verifica se foi numa posição válida
            if (cx >= 0 && cx < matrizTabuleiro.length && 
                cy >= 0 && cy < matrizTabuleiro[1].length){
                
                // troca o valor na matriz do tabuleiro
                if (matrizTabuleiro[cx][cy] == 0){
                    matrizTabuleiro[cx][cy] = 1;
                }else{
                    matrizTabuleiro[cx][cy] = 0;
                }
            }

            // força o painel a redesenhar/atualizar
            this.repaint();
        }

        @Override
        protected void paintComponent(Graphics g){
            Graphics2D g2 = (Graphics2D) g.create();

            // desenha o tabuleiro
            for (int i = 0; i < matrizTabuleiro.length; i++){
                for (int j = 0; j < matrizTabuleiro[i].length; j++){
                    // muda a cor pra desenhar se é agua ou não
                    if(matrizTabuleiro[i][j] == 0){
                        g2.setColor(Color.BLUE); 
                    }else{
                        g2.setColor(Color.YELLOW);
                    }
                    // desenha retangulos de 40x40, a 100 pixels da borda
                    g2.fillRect(
                            i * ExemploTabuleiro.TAMANHO + 100, 
                            j * ExemploTabuleiro.TAMANHO + 100, 
                            ExemploTabuleiro.TAMANHO, 
                            ExemploTabuleiro.TAMANHO);
                    
                    // linhas divisorias
                    g2.setColor(Color.WHITE); 
                    g2.drawRect(
                            i * ExemploTabuleiro.TAMANHO + 100, 
                            j * ExemploTabuleiro.TAMANHO + 100, 
                            ExemploTabuleiro.TAMANHO, 
                            ExemploTabuleiro.TAMANHO);
                }
            }

            g2.dispose();
        }
    }
}

Obs: pode haver alguns problemas, foi um código rápido.

Durante a partida, você pode armazenar qual o turno atual (do jogador ou do adversário) e reagir de acordo. Ex: na vez do adversário, os cliques do jogador são ignorados.

O bom é que com Java2D você consegue desenhar o que quiser: imagens, linhas retângulos, elipses, adicionar alguns efeitos, etc. E não depende de muitos componentes visuais do Swing. Veja mais aqui: http://pontov.com.br/site/java/48-java2d/93-uma-visao-rapida-sobre-o-java-2d

Abraço.

IghorSantiago

Fala TerraSkilll,

Mandei pro Ofidomundo o link do repositório, se estiver certo, eu coloco aqui no post depois.

O meu código está praticamente igual ao que você falou.
O tabuleiro eu crio com uma clase (class Botao) que estende JLabel usando um loop que monta os “botões” em um JPanel e armazena cada botao em uma matriz.
Dentro da classe Botao, eu tenho os métodos para pegar linha e coluna de cada botao e todo botao é criado com mouseListener.
Cada botao tem um “Estado” (VAZIO, AGUA, NAVIO).
Eles são inicializados como AGUA, quando posiciono os navios, cada botao que recebe um pedaço do navio, tem seu estado alterado de AGUA para NAVIO, então, quando alguém atira, eu pego o estado do botao selecionado e mostro o resultado.

Não sei se expliquei direito, mas acho que é por aí.

IghorSantiago

Diego, coloquei os Sysout’s e deu o que eu já imaginava.
A orientação ele ta pagando do JOptionPane e a linha e a coluna vem zerado.
O primeiro navio é posicionado, retornando true. O próximo, retorna false, pq a

D
linha = btn.getLinha(); // retornando zero
coluna = btn.getColuna(); // retornando zero

Já descobriu um problema, agora vc tem que resolver.

Só uma ideia:

Botao[][] botões = new Botao[LINHAS][COLUNAS];
Botao selecionado = null;

// constrói os botoes
for (int l = 0; l < LINHAS; l++) {
  for (int c = 0; c < COLUNAS; c++) {
    botões[l][c] = new Botao();
    add(botões[l][c]); // adiciona na tela
    botões[l][c].setLinha(l);
    botões[l][c].setColuna(c);
    // adiciona o evento, pode ser o MouseListener se preferir
    botões[l][c].addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e) {
        selecionar((Botao) e.getSource());
      }
    });
  }
}

// seleciona
public void selecionar(Botao btn) {
  selecionado = btn;
}

// no posicionaPlayer
linha = selecionado.getLinha();
coluna = selecionado.getColuna();
Ofidomundo

@IghorSantiago ele tem razão, essa seria uma boa saída, pois o que você faz lá é criar novos botões sem posicionamento, onde deveria estar na verdade recebendo talvez a tabela toda ou todos os botoes da tela

Ofidomundo

@IghorSantiago esquece isso, ja sei

Ofidomundo

adciona um action listener para o tabuleiro player, quando estiverem em estado.Aguardo você manda ele para o btn que esta na classe!?

Ofidomundo

deu para entender? kkkkk

IghorSantiago
public void criaTabuleiro(JPanel tela, Botao [][] tabuleiro, String jogador) {
	
	for(int i = 0; i < 10; i++) {

		for(int g = 0; g < 10; g++) {

			tabuleiro[i][g] = new Botao();
			tabuleiro[i][g].setName(jogador + " " + String.valueOf(i * 10 + g));
			tabuleiro[i][g].setEstado(Estado.AGUA);
			tabuleiro[i][g].setId(0);
			tabuleiro[i][g].setLinha(i);
			tabuleiro[i][g].setColuna(g);
			tabuleiro[i][g].setToolTipText("ID: " + String.valueOf(tabuleiro[i][g].getId()));

			tela.add(tabuleiro[i][g]);
		}
	}

	if(jogador.equals("Player")) {

		player.setNome(JOptionPane.showInputDialog(null, "Digite seu nome:"));
		tela.setBorder(BorderFactory.createTitledBorder("Alm. " + player.getNome()));
	}
	else
		tela.setBorder(BorderFactory.createTitledBorder("Alm. Computador"));
}

Na classe Botao():

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 void init() {
	
	setText("");
	setOpaque(true);
	setBorder(BorderFactory.createLineBorder(Color.BLACK));
	setPreferredSize(new Dimension(30, 30));
	setHorizontalAlignment(SwingConstants.CENTER);
	setBackground(Color.LIGHT_GRAY);
	setIcon(imagem.mar);
	estado = Estado.AGUA;
	
	Botao esteBotao = this;
	
	addMouseListener(new MouseAdapter() {
		
		@Override
		public void mouseClicked(MouseEvent e) {
			
			selecionado = esteBotao;
			JOptionPane.showMessageDialog(null, "Botão selecionado"
												+ "\n[" + selecionado.getLinha()
												+ "][" + selecionado.getColuna()
												+ "] - " + selecionado.getEstado());
		}
	});
IghorSantiago

Não entendi, foi mal

Ofidomundo

a função get selecionado retorna o botao que foi clickado, voce precisa de algo parecido, porem na classe player para que funcione com a matriz de botões toda

D

Evento fora do botão é melhor

tabuleiro[i][g].setLinha(i);
tabuleiro[i][g].setColuna(g);
tabuleiro[i][g].addMouseListener(new MouseAdapter() {
  public void mouseClicked(MouseEvent e) {
    Botao btn = (Botao) e.getSource(); // obtem o btn selecionado
    posicionaPlayer(btn); // passa como parâmetro para a função
  }
}

e

public void posicionaPlayer(Botao btn) {
  navio.posicionaNavio("?", orientacao, btn.getLinha(), btn.getColuna(), navio, tabuleiroPlayer);
}

Código para somente para testar:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;

public class BatalhaNaval extends JFrame {
    int LARGURA = 10;
    int ALTURA = 6;
    JLabel[][] campoBtns = new JLabel[ALTURA][LARGURA];
    
    enum ESTADO {
        JOGADOR_POSICIONANDO,
        COMPUTADOR_POSICIONANDO,
        JOGADOR_JOGANDO,
        COMPUTADOR_JOGANDO;
    }
    
    enum DIRECAO {
        HORIZONTAL, VERTICAL;
    }
    
    int tamanho = 3;// todos serao 3
    
    ESTADO estado = ESTADO.JOGADOR_POSICIONANDO; // inicia com jogador posicionando
    DIRECAO direcao = DIRECAO.HORIZONTAL;
    
    Border BLACK_BORDER = BorderFactory.createLineBorder(Color.BLACK, 3);
    Border GREEN_BORDER = BorderFactory.createLineBorder(Color.GREEN, 3);
    Border RED_BORDER = BorderFactory.createLineBorder(Color.RED, 3);
    
    
    public BatalhaNaval() {
        setLayout(new GridLayout(ALTURA, LARGURA));
        for (int l = 0; l < ALTURA; l++) {
            for (int c = 0; c < LARGURA; c++) {
                add(campoBtns[l][c] = criarCampoBtn(l, c));
            }
        }
        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }
    
    public JLabel criarCampoBtn(int linha, int coluna) {
        JLabel btn = new JLabel();
        btn.setPreferredSize(new Dimension(36,36));
        btn.setOpaque(true);
        btn.setBorder(BLACK_BORDER);
        btn.setBackground(Color.BLUE);
        MouseAdapter ma = new MouseAdapter(){
            @Override
            public void mouseReleased(MouseEvent e) {
                switch(estado) {
                    case JOGADOR_POSICIONANDO:
                        System.out.println("Inseriu navio: "+posicionarJogador(linha, coluna));
                        return;
                }
            }
            @Override
            public void mouseEntered(MouseEvent e) {
                switch(estado) {
                    case JOGADOR_POSICIONANDO:
                        destacarPosicao(linha, coluna);
                        return;
                }
            }
            
            @Override
            public void mouseExited(MouseEvent e) {
                switch(estado) {
                    case JOGADOR_POSICIONANDO:
                        for (int l = 0; l < ALTURA; l++) {
                            for (int c = 0; c < LARGURA; c++) {
                                // limpa as bordas
                                campoBtns[l][c].setBorder(BLACK_BORDER);
                            }
                        }
                        return;
                }
            }
            
            void destacarPosicao(int linha, int coluna) {
                int tamanhoHorizontal = 1;
                int tamanhoVertical = 1;
                if (direcao == DIRECAO.HORIZONTAL) tamanhoHorizontal = tamanho;
                if (direcao == DIRECAO.VERTICAL) tamanhoVertical = tamanho;
                // se tem espaço para por o navio
                boolean espacoOk = coluna + tamanhoHorizontal <= LARGURA
                        && linha + tamanhoVertical <= ALTURA;
                for (int l = linha; l < Math.min(linha + tamanhoVertical, ALTURA); l++) {
                    for (int c = coluna; c < Math.min(coluna + tamanhoHorizontal, LARGURA); c++) {
                        // não esta ocupado e tem espaco
                        boolean ok = !campoBtns[l][c].getText().equals("x") && espacoOk;
                        campoBtns[linha][c].setBorder(ok ? GREEN_BORDER : RED_BORDER);
                    }
                }
            }
            
            boolean posicionarJogador(int linha, int coluna) {
                int tamanhoHorizontal = 1;
                int tamanhoVertical = 1;
                if (direcao == DIRECAO.HORIZONTAL) tamanhoHorizontal = tamanho;
                if (direcao == DIRECAO.VERTICAL) tamanhoVertical = tamanho;
                // se tem espaço para por o navio E não colide com outros navios
                if (coluna + tamanhoHorizontal <= LARGURA
                        && linha + tamanhoVertical <= ALTURA
                        && !verificarColisoes(linha, coluna, tamanhoHorizontal, tamanhoVertical)) {
                    // coloca o navio
                    for (int l = linha; l < linha + tamanhoVertical; l++) {
                        for (int c = coluna; c < coluna + tamanhoHorizontal; c++) {
                            campoBtns[l][c].setBackground(Color.YELLOW);
                            campoBtns[l][c].setText("x");
                        }
                    }
                    return true;
                } else {
                    return false;
                }
            }
            
            // verifica colisoes com outros navios
            boolean verificarColisoes(int linha, int coluna, int tamanhoHorizontal, int tamanhoVertical) {
                for (int l = linha; l < linha + tamanhoVertical; l++) {
                    for (int c = coluna; c < coluna + tamanhoHorizontal; c++) {
                        if (campoBtns[l][c].getText().equals("x")) {
                            return true;
                        }
                    }
                }
                return false;
            }
        };
        btn.addMouseListener(ma);
        btn.addMouseMotionListener(ma);
        return btn;
    }
}
Ofidomundo

ai fazendo um tipo de listenner no botão, variando cada ação dependendo de cada “fase” do jogo, seja ela preparação, jogo ou final

IghorSantiago

Funcionou!
Coloquei esse pedaço no meu código e foi.

Só não entendi uma coisa:
Assim ele vai chamar o evento sempre que eu clicar nos botões. Como farei na hora de atirar?

Obrigado Diego!

IghorSantiago

Acho que eu vou ter que fazer isso agora pra poder atirar, depois de posicionar os navios…

D
int estado;
  final int POSICIONANDO = 0;
  final int ATIRANDO = 1;
  public void mouseClicked(MouseEvent e) {
    if (estado == POSICIONANDO) {
      Botao btn = (Botao) e.getSource(); // obtem o btn selecionado
      posicionaPlayer(btn); // passa como parâmetro para a função
    } else if (estado == ATIRANDO) {
      /***/
    }
  }
IghorSantiago

Coloquei um if.

public void posicionaPlayer(Botao btn) {

	int orientacao = 0, linha = 0, coluna = 0;
	
	if(navios <= 5) {
		
		navio = navio.constroiNavio(navios);
		
		JOptionPane.showMessageDialog(
				null, "Posicione o " + navio.getNome() + "."
					+ "\nEsse navio ocupa " + navio.getTamanho() + " espaços."
					+ "\nEscolha o primeiro espaço que ele irá ocupar...");
	
		Object[] opcoes = {"Horizontal", "Vertical"};
	
		orientacao = JOptionPane.showOptionDialog(null, 
							"Escolha a orientação do navio",
							"Escolha",
							JOptionPane.YES_NO_CANCEL_OPTION,
							JOptionPane.QUESTION_MESSAGE,
							null,
							opcoes,
							opcoes[1]);
		
		if(btn == null){
			System.out.println("btn nulo");
		}
		if(btn.selecionado == null){
			System.out.println("selecionado nulo");
		}
		
		linha = btn.getLinha();
		coluna = btn.getColuna();
		
		if(navio.getTamanho() != 0) {

			if(orientacao < 2) {
				
				if(linha < 10) {

					if(coluna < 10) {

						if(navio.posicionaNavio("C", orientacao, linha, coluna, navio, tabuleiroPlayer)) {

							navios++;

						}
					}
				}
			}
		}
	}
	else
		jogo.vez();
	
	navio.posicionaNavio("P", orientacao, linha, coluna, navio, tabuleiroPlayer);
}

Se navios (variável que contabiliza os navios) for menor que 5 (quantidade máxima de navios), ele posiciona o próximo aonde eu cliquei. Se já tiver os 5 navios, ele chama o método “vez()”, que vê de quem é o turno e chama o método pra atirar.

Amanhã eu vou ver se tudo funciona e comento aqui…

Obrigado a todos pela força!

IghorSantiago
Posiciona os navios (Computador e Player)

Atira (Player)

Quando chamo o método pro computador atirar, ele da NPE. Só não entendi porque que ele entra no if e depois dá a exceção. As 2 linhas são praticamente iguais, só que um pega o estado e a outra seta.

Ofidomundo

se vc prestar atenção no que esta escrito, o pocisionamento esta retornando nulo, entao ele da null pointer pois player.tabuleiroplayer[l][c] esta nulo

IghorSantiago

Eu só não entendi porque que ele entra no if então, era pra dar NPE na linha 53.

Ofidomundo

na verdade não

um enum para obj nulo retorna sempre 0 não!?

null.getEstado == Estado.Vazio

IghorSantiago

Mas se é null, ele não deveria chamar o método getEstado(), ou deveria?

Ofidomundo

da um syso(player.tabuleiroplayer[l][c]) e veja o que retorna

IghorSantiago

retorna null.
Não entendo o porque.

Ofidomundo

seria o botão [l][c] que esta nulo, mas isso é realmente estranho…

IghorSantiago

Mas não era pra estar null. Como a linha e a coluna eu gero randomicamente, na teoria, ele tá falando que meu tabuleiro inteiro está null. Só que na hora de posicionar os navios, ele não dá erro.

Ofidomundo

tenta colocar um for para ver se esta realmente nulo, senão a matriz não foi criada ou sla

IghorSantiago

Eu sei que a matriz foi criada corretamente porque:
- O tabuleiro é “desenhado” na tela;
- Os navios são posicionados corretamente.

Colocar um for aonde? Pra ele tentar em todas as posições?
Coloquei agora alguns valores na mão, ele sempre retorna null.

Ofidomundo

um for para ver qual botão esta ou não nulo, mas bem se os testes que você fez foram todos nulos então a matriz que vocês está usando teve erro de atribuição e não de criação.

IghorSantiago

Como assim erro de atribuição?

Ofidomundo

a matriz que vocês usa nessa classe não é a matriz real utilizada no tabuleiro, por isso esta com esse erro

IghorSantiago

Então não sei.
Olhei de novo aqui, não tem nenhuma outra matriz.

Ofidomundo

desculpa, não a matriz em geral, mas seus elementos não estão no método que você esta usando…

Ofidomundo

coloca um syso(player.tabuleiroplayer) e posta o que ele retorna para ver o que rola

IghorSantiago

Ofidomundo

isso : player.tabuleiroplayer esta vom um botão dentro !? tente pegar o estado dele, acho que é o btn clicado

IghorSantiago
player.tabuleiroPlayer é a matriz que guarda os botões que formam o tabuleiro do player.

Não tem como dar player.tabuleiroPlayer.getEstado();

 player.tabuleiroPlayer[linha][coluna].getEstado();
staroski

Ao invés de ficar postando screenshots, posta o código fonte das classes.
Formata direitinho no fórum usando o botão de "Texto pré-formatado": </>
Aí fica fácil para alguém reproduzir e identificar o problema.

IghorSantiago

O problema é que são várias classes.

Ofidomundo

tenta coloar uma branch no git dnv

IghorSantiago

Só em casa, o pc do trabalho é todo bloqueado.

IghorSantiago

Segue link do repositório:

https://bitbucket.org/ighorsantiago/batalhanaval/src/master/

O “Jogo1.java” foi só pra não perder o que eu tinha feito, acabei subindo junto sem querer.

Ofidomundo

percebi que o computador pode “colocar” um naviu em cima do outro

IghorSantiago

Não pode, tem um método de verificação.
Ele verifica se o navio cabe na posição escolhida (sorteada, no caso do computador) e se já tem algum navio em algum dos quadrados que o navio vai ocupar.

Ofidomundo

sim, tava na versão antiga ainda, desculpa

Ofidomundo

eu arrumei

Ofidomundo
public void atiraPlayer(Botao btn) {
	player = TelaPrincipal.getPlayer();
	if(btn.getEstado() == Estado.AGUA) {

		btn.setEstado(Estado.VAZIO);
		btn.setIcon(imagem.agua);
	}
Ofidomundo

coloquei um pegar a tela player da tela inicial e realmente funcionou, porem ele só deixa eu atirar no campo do player e tem que dar uma forma de setar isso na inicialização da classse jogo e não onde eu coloquei

IghorSantiago

O problema é no tiro do computador, o do player tava funcionando.

Ofidomundo

sim, mas o player chama o tiro do computador

IghorSantiago

Sim.
Se eu clicar em algum botão e os navios já estiverem todos posicionados, ele chama o método de tiro do player.
Após o tiro do player, ele chama o do computador.
Ai ele dá erro, dizendo que o tabuleiro tá todo null.

Ofidomundo

o que não esta indo é o tiro do player no campo do computador, com o codigo que eu coloquei ele pega o campo do player e arruma o problema da matriz

Ofidomundo

IghorSantiago

Ofidomundo

Ofidomundo

Primeiro, para de chamar o Pc pelo player, chama ele pela tela inicial e fica fazendo o set das matrizes lá, ou cria as duas matrizes no “jogo” e só la.

IghorSantiago

Posso até tentar, mas inicialmente, eu tinha criado as matrizes na TelaPrincipal, porque é onde eu crio os tabuleiros. Mas deu algum erro (não me lembro qual era) que eu consegui resolver criando as matrizes nas classes Player e Computador.

IghorSantiago

Deu NPE, pq eu não inicializei, depois deu StackOverflow.

Ofidomundo

então deixa as matrizes no player e no pc, e antes de entrar na classe jogo pega as matrizes de lá

IghorSantiago

Alguma ideia de como?
Eu tentei criando uma matriz e passando direto e depois por get/set.
Eu só não entendo porque que o player atira e o computador dá erro, não faz sentido.

Ofidomundo

eu errei o bglh, fiz pela tela…

mas é só fazer por get

Ofidomundo

é que tipo, a informação de qual player que é esta na tela!!

IghorSantiago

Eu tentei por get mas vinha null tbm.
Vou tentar aqui de novo.

Ofidomundo

Tela:

public static Botao[][] getPlayer() {
	      return player.getTabuleiroPlayer();
    }

Jogo:

player = TelaPrincipal.getPlayer();

Tela2:

public void criaTabuleiro(JPanel tela, Botao [][] tabuleiro, String jogador) {
	
	for(int i = 0; i < 10; i++) {

		for(int g = 0; g < 10; g++) {

			tabuleiro[i][g] = new Botao();
			tabuleiro[i][g].setName(jogador + " " + String.valueOf(i * 10 + g));
			tabuleiro[i][g].setEstado(Estado.VAZIO);
			tabuleiro[i][g].setId(0);
			tabuleiro[i][g].setLinha(i);
			tabuleiro[i][g].setColuna(g);
			tabuleiro[i][g].setToolTipText("ID: " + String.valueOf(tabuleiro[i][g].getId()));
			tabuleiro[i][g].addMouseListener(new MouseAdapter() {
				
				@Override
				public void mouseClicked(MouseEvent e) {
					
					Botao btn = (Botao) e.getSource();
					if(player.navios <= 5) { player.posicionaPlayer(btn); }
					else{
						if (jogadorVez) {
							jogo.atiraPlayer(btn);		
							jogadorVez = false;
						}else {
							criaTabuleiro(tela, tabuleiro, "computador");
							jogadorVez = true;
						}
					};
				}
			});
			
			tela.add(tabuleiro[i][g]);
		}
	}

	if(jogador.equals("Player")) {

		player.setNome(JOptionPane.showInputDialog(null, "Digite seu nome:"));
		tela.setBorder(BorderFactory.createTitledBorder("Alm. " + player.getNome()));
	}
	else
		tela.setBorder(BorderFactory.createTitledBorder("Alm. Computador"));
}
IghorSantiago

Posso ter entendido errado, mas, na tela 2, ele não vai criar um tabuleiro toda vez que jogadorVez for falso? (ou seja, turno sim, turno não)

Ofidomundo

gaf nivel hard, sorry

jogo.atiraPlayer(btn);		
	jogo.atiraComputador();

na vdd é só isso

Ofidomundo
public static Computador getComputador() {
	return computador;
}
IghorSantiago

Hahaha
Acontece.
Beleza, quando conseguir fazer as modificações e testar e posto aqui.

Ofidomundo

eu fui trocando um monte de coisa q eu tinha feito e q tava com erro, dps da um commit hahahha

apaguei tudo

IghorSantiago

Hahaha
Blz

staroski

Ai, ai, ai… Precisa ser estático?

Ofidomundo

sim

IghorSantiago

Porque precisa ser estático?
Vou fazer as alterações e o teste agora.

IghorSantiago

No caso, esse “player” teria que ser uma matriz né?

IghorSantiago

Continua dando o mesmo erro, no mesmo lugar.

Ofidomundo

desculpa esse metodo get é return player,

Ofidomundo

para que voce chame ele na classe jogo, sem ter que declarar

IghorSantiago

Fiz uma POG aqui e funcionou… rsrs
Coloquei os métodos de ‘tiro’ (atiraPlayer() e atiroComputador()) dentro da classe Player…

Ofidomundo

perfeito!!

IghorSantiago

Agora vou só fazer alguns ajustes, como tratamento de erros e melhorar a pontaria do computador.

Muito obrigado a todos pela ajuda!

Ofidomundo

eu devo é me desculpar por complicar tudo kk

IghorSantiago

Ajudou muito!

Criado 19 de julho de 2018
Ultima resposta 26 de jul. de 2018
Respostas 101
Participantes 6