Eu estou fazendo um trabalho para a disciplina de programação concorrente, no qual estou implementando o problema do Pare-Siga em uma simulação do Pacman. Compilando uma só vez, as vezes eu executo e dá certo, outras vezes dá errado, depois dá certo de novo, depois errado, não sei o que se passa.
Não aparece nenhum erro, algumas vezes. Cada thread é responsável pela movimentação de um personagem na tela. As vezes, todos se movem, tudo certinho, outra hora, um fica parado o tempo todo, outra hora todos se mexem, outra hora um outro personagem fica parado, isso tudo com o mesmo .class, só executo de novo e fica diferente, dando certo ou não.
Outras vezes, aparece o seguinte erro:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException at com.sun.scenario.animation.AbstractMasterTimer.timePulseImpl(AbstractMasterTimer.java:344) at com.sun.scenario.animation.AbstractMasterTimer$MainLoop.run(AbstractMasterTimer.java:267) at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:506) at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490) at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319) at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) at java.lang.Thread.run(Thread.java:745)
Não sei bem qual é a classe ou a parte do código que está gerando essas situações, mas vou colocar aqui algumas das classes.
Controle da tela:
package controles; // ControlePacman se encontra no pacote controles // As importações aqui... public class ControlePacman implements Initializable { // Atributos da classe @FXML private AnchorPane anchorBase; @FXML private Button sair; @FXML public ImageView imgPacman; Pacman pacman; @FXML public ImageView imgFantasminha; Fantasminha fantasminha; @FXML public ImageView imgFantasmaRight; FantasmaRight fantasmaRight; @FXML public ImageView imgFantasmaLeft; FantasmaLeft fantasmaLeft; @FXML private Button botaoVoltar; @FXML private Label labelModo; @FXML private Label labelMusica; public boolean pacmanPassando; public boolean fantasmaPassando; public ControleInicio tela; public static enum Status {DO, DONT}; // Opcoes de um personagem, se deve ser mover ou nao /* ******************************************************************* * Metodo: ControlePacman * Funcao: construtor da classe de mesmo nome * Parametros: nao possui parametros * Retorno: nao possui retorno ******************************************************************** */ public ControlePacman() { imgFantasminha = new ImageView(); // Inicializando ImageView imgFantasmaRight = new ImageView(); // Inicializando ImageView imgFantasmaLeft = new ImageView(); // Inicializando ImageView imgPacman = new ImageView(); // Inicializando ImageView anchorBase = new AnchorPane(); // Inicializando AnchorPane sair = new Button(); // Incializando Button botaoVoltar = new Button(); // Inicializando Button } // Fim do construtor /* ******************************************************************* * Metodo: initialize * Funcao: primeiro metodo executado quando a tela e chamada * Parametros: URL e ResourceBundle * Retorno: void ******************************************************************** */ @Override public void initialize(URL location, ResourceBundle resources) { imgFantasmaRight.setImage(new Image("/imagens/fantasmaDO2.png")); // Definindo a imagem imgFantasmaLeft.setImage(new Image("/imagens/fantasmaDO1.png")); // Definindo a imagem pacman = new Pacman(); // Inicializando a thread fantasminha = new Fantasminha(); // Inicializando a thread fantasmaRight = new FantasmaRight(); // Inicializando a thread fantasmaLeft = new FantasmaLeft(); // Inicializando a thread fantasminha.setTela(this); // Passando o controle para fantasminha fantasminha.start(); // Colocando-a em estado de pronto pacman.setTela(this); // Passando o controle para pacman pacman.start(); // Colocando-a em estado de pronto fantasmaRight.setTela(this); // Passando o controle para fantasmaRight fantasmaRight.start(); // Colocando-a em estado de pronto fantasmaLeft.setTela(this); // Passando o controle para fantasmaLeft fantasmaLeft.start(); // Colocando-a em estado de pronto } // Fim de initialize /* ******************************************************************* * Metodo: setTela * Funcao: receber o controle da tela de inicio * Parametros: objeto de ControleInicio * Retorno: void ******************************************************************** */ public void setTela(ControleInicio tela) { this.tela = tela; } // Fim de setTela /* ******************************************************************* * Metodo: setVelocidade * Funcao: configurar as velocidades dos personagens * Parametros: dois inteiros, as velocidades * Retorno: void ******************************************************************** */ public void setVelocidade(int speed1, int speed2) { fantasminha.setVelocidade(speed1); fantasmaRight.setVelocidade(speed1); fantasmaLeft.setVelocidade(speed1); pacman.setVelocidade(speed2); } // Fim de setVelocidade /* ******************************************************************* * Metodo: getPassando * Funcao: avisa se um dos personagens esta passando pela area compartilhada * Parametros: String com o nome do personagem * Retorno: boolean ******************************************************************** */ public boolean getPassando(String quem) { switch(quem) { case "pacman": // Para o caso do pacman return pacmanPassando; // Retorna o valor verdade case "fantasminha": // Para o caso do fantasminha return fantasmaPassando; // Retorna o valor verdade } // Fim do switch return false; } // Fim de getPassando /* ******************************************************************* * Metodo: setPassando * Funcao: para informar o controle se algum personagem esta passando * pela area compartilhada * Parametros: um boolean e o nome do personagem * Retorno: void ******************************************************************** */ public void setPassando(boolean flag, String quem) { switch(quem) { case "pacman": // Para o caso do pacman pacmanPassando = flag; // Registra o valor verdade case "fantasminha": // Para o caso do fantasminha fantasmaPassando = flag; // Registra o valor verdade } // Fim do switch } // Fim de setPassando /* ******************************************************************* * Metodo: moveEmY * Funcao: mover os personagens pelo eixo y * Parametros: double, inteiro e string * Retorno: animacao da classe TranslateTransition ******************************************************************** */ public TranslateTransition moveEmY(double tempo, int destino, String quem) { TranslateTransition transicao = new TranslateTransition(); // Criando e instanciando transicao Platform.runLater(new Runnable() { @Override public void run() { transicao.setDuration(Duration.seconds(tempo)); // Definindo duracao da transicao switch(quem) { // Para definir quem esta se movendo case "fantasminha": // Se for um movimento de Fantasminha transicao.setNode(imgFantasminha); break; case "fantasmaRight": // Se for um movimento de FantasmaRight transicao.setNode(imgFantasmaRight); break; case "fantasmaLeft": // Se for um movimento de FantasmaLeft transicao.setNode(imgFantasmaLeft); break; case "pacman": // Se for um movimento de Pacman transicao.setNode(imgPacman); break; default: System.out.println("Algo deu errado!"); } transicao.setToY(destino); // Movendo o personagem ate o local desejado transicao.play(); // Autoexplicativo } // Fim de run }); // Fim de Platform return transicao; } // Fim de moveEmY /* ******************************************************************* * Metodo: moveEmX * Funcao: mover os personagens no eixo X * Parametros: double, int e string * Retorno: animacao da classe TranslateTransition ******************************************************************** */ public TranslateTransition moveEmX(double tempo, int destino, String quem) { TranslateTransition transicao = new TranslateTransition(); // Criando e instanciando a transicao Platform.runLater(new Runnable() { @Override public void run() { transicao.setDuration(Duration.seconds(tempo)); // Definindo a duracao da transicao switch(quem) { // Para definir quem esta se movendo case "fantasminha": // Se for um movimento de Fantasminha transicao.setNode(imgFantasminha); break; case "fantasmaRight": // Se for um movimento de FantasmaRight transicao.setNode(imgFantasmaRight); break; case "fantasmaLeft": // Se for um movimento FantasmaLeft transicao.setNode(imgFantasmaLeft); break; case "pacman": // Se for for um movimento de Pacman transicao.setNode(imgPacman); break; } // Fim de switch transicao.setToX(destino); // Movendo o personagem ate o local desejado transicao.play(); // Autoexplicativo } // Fim de run }); // Fim de Platform return transicao; } // Fim de moveEmX /* ******************************************************************* * Metodo: chegouDireita * Funcao: informar quando algum personagem entrou na regiao critica * pelo lado direito * Parametros: void * Retorno: void ******************************************************************** */ public void chegouDireita() { controleEsquerda(Status.DONT); // Chamando metodo controleEsquerda } // Fim de chegouDireita /* ******************************************************************* * Metodo: saiuEsquerda * Funcao: informar quando algum perosnagem deixou a regiao critica pelo * lado esquerdo * Parametros: void * Retorno: void ******************************************************************** */ public void saiuEsquerda(String quem) { switch(quem) { case "pacman": if (fantasmaPassando) controleEsquerda(Status.DONT); // Chamando o metodo controleEsquerda controleEsquerda(Status.DO); break; case "fantasminha": if (pacmanPassando) controleEsquerda(Status.DONT); controleEsquerda(Status.DO); break; } // Fim do switch } // Fim de saiu Esquerda /* ******************************************************************* * Metodo: chegouEsquerda * Funcao: informar quando algum personagem chegou na regiao critica * pelo lado esquerdo * Parametros: void * Retorno: void ******************************************************************** */ public void chegouEsquerda() { controleDireita(Status.DONT); // Chamando o metodo controleDireita } // Fim de chegouEsquerda /* ******************************************************************* * Metodo: saiuDireita() * Funcao: informar quando algum personagem deixou a regiao critica pelo * pelo lado direito * Parametros: void * Retorno: void ******************************************************************** */ public void saiuDireita(String quem) { switch(quem) { case "pacman": if (fantasmaPassando) controleDireita(Status.DONT); // Chamando o metodo controleEsquerda controleDireita(Status.DO); break; case "fantasminha": if (pacmanPassando) controleDireita(Status.DONT); controleDireita(Status.DO); break; } // Fim do switch } // Fim de saiuDireita /* ******************************************************************* * Metodo: controleDireita * Funcao: fazer o fantasma da esquerda levnatar ou abaixar a placa * Parametros: Status * Retorno: void ******************************************************************** */ public void controleDireita(Status status) { Platform.runLater(new Runnable() { @Override public void run() { if (status == Status.DONT) { imgFantasmaLeft.setImage(new Image("/imagens/fantasmaDONT1.png")); // Levantando a placa } // Fim do if else { imgFantasmaLeft.setImage(new Image("/imagens/fantasmaDO1.png")); // Abaixando a placa } // Fim do else } // Fim de run }); // Fim de Platform } // Fim de controleDireita /* ******************************************************************* * Metodo: controleEsquerda * Funcao: fazer o fantasma da direita levantar ou abaixar a placa * Parametros: Status * Retorno: void ******************************************************************** */ public void controleEsquerda(Status status) { Platform.runLater(new Runnable() { @Override public void run() { if (status == Status.DONT) { imgFantasmaRight.setImage(new Image("/imagens/fantasmaDONT2.png")); // Levantando a placa } // Fim de if else { imgFantasmaRight.setImage(new Image("/imagens/fantasmaDO2.png")); // Levantando a placa } // Fim de else } // Fim de run }); // Fim de Platform } // Fim de controleEsquerda /* ******************************************************************* * Metodo: fechar * Funcao: encerrar o programa * Parametros: evento * Retorno: void ******************************************************************** */ @FXML public void fechar(ActionEvent event) { System.exit(0); // Encerrando o programa } // Fim de fechar } // Fim de ControlePacman
Da thread que comanda o Pacman:
package personagens; // Pacman se encontra no pacote personagens // As importações aqui... public class Pacman extends Thread { // E uma thread // Atributos da classe Pacman public ControlePacman tela; private int velocidade; private int contador; private Timeline tempo; /* ******************************************************************* * Metodo: Pacman * Funcao: metodo construtor dessa classe * Parametros: void * Retorno: nao retorna nada ******************************************************************** */ public Pacman() { velocidade = 1; // Inicializando a velocidade como 1 contador = 0; // Inicializando o contador como 1 } // Fim de construtor /* ******************************************************************* * Metodo: setTela * Funcao: recebendo o controle * Parametros: objeto de ControlePacman * Retorno: void ******************************************************************** */ public void setTela(ControlePacman tela) { this.tela = tela; } // Fim de setTela /* ******************************************************************* * Metodo: setVelocidade * Funcao: configurar a velocidade do fantasma da direita * Parametros: inteiro com a velocidade * Retorno: void ******************************************************************** */ public void setVelocidade(int velocidade) { this.velocidade = velocidade; } // Fim de setVelocidade /* ******************************************************************* * Metodo: run * Funcao: primeiro metodo a ser executado quando a thread for acionada * Parametros: void * Retorno: void ******************************************************************** */ @Override public void run() { try { sleep(1000); tela.imgPacman.setOpacity(1); // Torna visivel o pacman tempo = new Timeline(new KeyFrame(Duration.seconds(0), (a) -> { tela.moveEmX(velocidade, 55, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 250, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 180, "pacman"); })); tempo.play(); trajeto(); // Chamando o metodo trajeto } catch(Exception pac) { pac.getStackTrace(); } } // Fim de run /* ******************************************************************* * Metodo: trajeto * Funcao: funcao recursiva que define o trajeto performado pelo pacman * Parametros: void * Retorno: void ******************************************************************** */ private void trajeto() { try { tempo = new Timeline(new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 300, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 360, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 180, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 485, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 300, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 180, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 360, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 300, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 240, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 180, "pacman"); })); tempo.play(); sleep(velocidade * contador); while(tela.getPassando("fantasminha")) { // Esperando o fantasma passar pela zona critica sleep(500); } // Fim do while tempo = new Timeline(new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.setPassando(true, "pacman"); // Avisando que a pista esta ocupada tela.chegouEsquerda(); // Pedindo para o fantasma fechar a pista }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 125, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 540, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 0, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.setPassando(false, "pacman");// Avisando que a pista esta liberada tela.saiuDireita("pacman"); // Pedindo para o fantasma abaixar a placa }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 650, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 540, "pacman"); })); tempo.play(); sleep(velocidade * contador); while(tela.getPassando("fantasminha")) { // Esperando o fantasma atravessar a regiao critica sleep(500); } // Fim de while tempo = new Timeline(new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.setPassando(true, "pacman"); // Avisando que a pista esta ocupada tela.chegouDireita(); // Pedindo para o fantasma fechar a pista }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 125, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 180, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 240, "pacman"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.setPassando(false, "pacman"); // Avisando que a pista esta livre tela.saiuEsquerda("pacman"); // Pedindo para o fantasma liberar a pista })); tempo.play(); sleep(velocidade * contador); trajeto(); // Chamada recursiva } catch (Exception pac) { pac.getStackTrace(); } } // Fim de trajeto } // Fim de Pacman
Da classe de um dos fantasmas:
package personagens; // Fantasminha esta no pacote personagens // importações... public class Fantasminha extends Thread { // Atributos dessa classe public ControlePacman tela; private int velocidade; private int contador; private Timeline tempo; /* ******************************************************************* * Metodo: Fanstaminha * Funcao: metodo construtor dessa classe * Parametros: void * Retorno: nao retorna nada ******************************************************************** */ public Fantasminha() { velocidade = 1; // Inicializando a velocidade como 1 contador = 0; // Inicializando o contador com 0 } // Fim do construtor /* ******************************************************************* * Metodo: setTela * Funcao: recebendo o controle * Parametros: objeto de ControlePacman * Retorno: void ******************************************************************** */ public void setTela(ControlePacman tela) { this.tela = tela; } // Fim de setTela /* ******************************************************************* * Metodo: setVelocidade * Funcao: configurar a velocidade do fantasma da direita * Parametros: inteiro com a velocidade * Retorno: void ******************************************************************** */ public void setVelocidade(int velocidade) { this.velocidade = velocidade; } // Fim de setVelocidade /* ******************************************************************* * Metodo: run * Funcao: primeiro metodo a ser executado quando a thread for acionada * Parametros: void * Retorno: void ******************************************************************** */ @Override public void run() { try { tela.imgFantasminha.setOpacity(1); // Deixando o fantasma visivel tempo = new Timeline(new KeyFrame(Duration.seconds(0), (a) -> { tela.moveEmY(velocidade, 175, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 290, "fantasminha"); })); tempo.play(); // Performando a animacao acima sleep(velocidade * contador); trajeto(); // Chamando a funcao trajeto } catch(Exception pac) { pac.getStackTrace(); } } // Fim de run /* ******************************************************************* * Metodo: trajeto * Funcao: funcao recursiva que define o trajeto feito pelo fantasma * Parametros: void * Retorno: void ******************************************************************** */ private void trajeto() { try { tempo = new Timeline(new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, -120, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 420, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 0, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 540, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, -120, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 0, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 420, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, -120, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 290, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 0, "fantasminha"); })); tempo.play(); sleep(velocidade * contador); while(tela.getPassando("pacman")) { // Esperando o pacman atravessar a regiao critiva sleep(500); } // Fim de while tempo = new Timeline(new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.setPassando(true, "fantasminha"); // Avisando que a pista esta ocupada tela.chegouDireita(); // Pedindo para o outro fantasma fechar a pista }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 175, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, -360, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 60, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.setPassando(false, "fantasminha"); // Avisando que a pista esta livre tela.saiuEsquerda("fantasminha"); // Pedindo para o outro fantasma liberar a pista }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, -480, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, -360, "fantasminha"); })); tempo.play(); sleep(velocidade * contador); while(tela.getPassando("pacman")) { // Esperando, caso o pacman esteja atravessando a regiao critiva sleep(500); } // Fim de while tempo = new Timeline(new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.setPassando(true, "fantasminha"); // Sinalizando que a pista esta sendo usada tela.chegouEsquerda(); // Pedindo para o outro fantasma levnatar a placa }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 175, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmX(velocidade, 0, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.moveEmY(velocidade, 290, "fantasminha"); }), new KeyFrame(Duration.seconds(++contador * velocidade), (b) -> { tela.setPassando(false, "fantasminha"); // Avisando que a pista esta livre tela.saiuDireita("fantasminha"); // Pedindo para o outro fantasma abaixar a placa })); tempo.play(); trajeto(); // Chamada recursiva } catch (Exception pac) { pac.getStackTrace(); } } // Fim de trajeto } // Fim de Fantasminha
Alguém pode me dar uma luz?