BatalhaNaval GUI

101 respostas
actionlistenerjava
I

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

T

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.

I

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.

S

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

I

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

M

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

I

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.

I

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]?

I

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?

O

coloca algum tipo de wait();

I

Fala Ofidomundo,

“Ofidomundo:

coloca algum tipo de wait();

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

O

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

I

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.

O

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

T

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++;
	}
}
I

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.

I

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.

O

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

T

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.

I

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í.

I

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();
O

@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

O

@IghorSantiago esquece isso, ja sei

O

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

O

deu para entender? kkkkk

I
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());
		}
	});
I

Não entendi, foi mal

O

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;
    }
}
O

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

I

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!

I

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) {
      /***/
    }
  }
I

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!

I
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.

O

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

I

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

O

na verdade não

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

null.getEstado == Estado.Vazio

I

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

O

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

I

retorna null.
Não entendo o porque.

O

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

I

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.

O

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

I

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.

O

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.

I

Como assim erro de atribuição?

O

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

I

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

O

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

O

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

I

O

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

I
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();
S

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.

I

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

O

tenta coloar uma branch no git dnv

I

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

I

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.

O

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

I

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.

O

sim, tava na versão antiga ainda, desculpa

O

eu arrumei

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

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

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

I

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

O

sim, mas o player chama o tiro do computador

I

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.

O

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

O

I

O

O

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.

I

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.

I

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

O

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

I

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.

O

eu errei o bglh, fiz pela tela…

mas é só fazer por get

O

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

I

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

O

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"));
}
I

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)

O

gaf nivel hard, sorry

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

na vdd é só isso

O
public static Computador getComputador() {
	return computador;
}
I

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

O

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

apaguei tudo

I

Hahaha
Blz

S

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

O

sim

I

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

I

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

I

Continua dando o mesmo erro, no mesmo lugar.

O

desculpa esse metodo get é return player,

O

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

I

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

O

perfeito!!

I

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

Muito obrigado a todos pela ajuda!

O

eu devo é me desculpar por complicar tudo kk

I

Ajudou muito!

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