Enquanto uma animação está executando a outra trava - runnable e thread

Alô turma do Guj!

Tô tentando fazer uma brincadeira aqui, usando a classe Runnable e Thread. Conheço um pouco de java, mas essas classes estou começando a usar. O problema que apareceu é:

Eu executo a classe Pinball clico no button start e a label azul (que depois vai ser a bola) se move no eixo y ate um ponto aleatório e outro método faz ela ir à esquerda. E então, a idéia é rebater com uma label Raq.

Tá tudo no começo. O problema é que enquanto a label azul está se movendo prá esquerda, e mesmo depois que ela para a label amarela raq trava e não consigo movê-la com as setas e as demais.

Só consigo fazer funcionar as setas reiniciando a aplicação ou antes de clicar em start.

Porque esse travamento enquanto as classes que movem o quadrado azul (bola) estão em execução? Onde está o erro? Me ajudem, por favor! Abaixo estão as classes envolvidas no programa.

package Run_;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.KeyEvent;
import java.lang.Math;
import java.util.Random;

public class Pinball extends JFrame implements ActionListener, KeyListener, ItemListener, FocusListener {
  
  private Container c;
  public static JLabel lBall, lEsq, lBaixo, lDir, lRaq, lPts, lExPts;
  private JLabel lTitTema, lPow;
  private JButton bSair, bStart, bReset;
  private ImageIcon iconTema, iconOk, iconSair, iconEstat, iconReset, iconVerif, iconIr, iconQuest, icon;
  public static JButton bDir, bStop;
  private JTextField t1;
  static int lRaqY = 0, lRaqX = 0;
  static int lBallY = 0, lBallX = 0;
  static int cont = 0, max=0, min=0;
  static int num_Al = 0;

  public Pinball() {
    super("Pinball");
    c = getContentPane();
    c.setLayout(null);
    c.setBackground(new java.awt.Color(255, 90, 50));

    t1 = new JTextField();
    t1.addKeyListener(this);

    iconTema = new ImageIcon("TitTema.jpg");
    iconOk = new ImageIcon("Tick.png");
    iconSair = new ImageIcon("exit.png");
    iconEstat = new ImageIcon("estat.png");
    iconReset = new ImageIcon("reset.png");
    iconVerif = new ImageIcon("verif.png");
    iconIr = new ImageIcon("ir.png");
    iconQuest = new ImageIcon("questao.png");
    icon = new ImageIcon("background.jpg");
    
    lBall  = new JLabel("");
    lBall.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    lBall.setBackground(new java.awt.Color(0, 210, 255));
    lBall.setOpaque(true);

    lTitTema  = new JLabel(" P I N B A L L ", JLabel.CENTER);
    lTitTema.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    lTitTema.setBackground(new java.awt.Color(148, 227, 0));//223
    lTitTema.setOpaque(true);

    lEsq  = new JLabel("");
    lEsq.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    lEsq.setBackground(new java.awt.Color(148, 227, 0));//223
    lEsq.setOpaque(true);

    lBaixo  = new JLabel("");
    lBaixo.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    lBaixo.setBackground(new java.awt.Color(148, 227, 0));//223
    lBaixo.setOpaque(true);

    lDir  = new JLabel("");
    lDir.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    lDir.setBackground(new java.awt.Color(148, 227, 0));//223
    lDir.setOpaque(true);

    lRaq  = new JLabel("");
    lRaq.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    lRaq.setBackground(new java.awt.Color(255, 235, 0));
    lRaq.setOpaque(true);

    lPts  = new JLabel("PONTOS:", JLabel.CENTER);
    lPts.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    lPts.setBackground(new java.awt.Color(255, 235, 0));
    lPts.setOpaque(true);

    lExPts  = new JLabel("0", JLabel.CENTER);
    lExPts.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    lExPts.setBackground(new java.awt.Color(192, 255, 255));
    lExPts.setOpaque(true);

    bDir  = new JButton(" >>> ");
    bDir.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    
    bSair  = new JButton("Sair",iconSair);
    bSair.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));

    bStart  = new JButton("Start");
    bStart.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    bStart.setVisible(true);

    bStop  = new JButton("Stop");
    bStop.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));
    bStop.setVisible(false);

    bReset  = new JButton("Reset");
    bReset.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0)));

    c.add(t1);
    c.add(lBall);
    c.add(lBaixo);
    c.add(lTitTema);
    c.add(lEsq);
    c.add(lDir);
    c.add(lRaq);
    c.add(lPts);
    c.add(lExPts);
    c.add(bStop);
    c.add(bReset);
    c.add(bSair);
    c.add(bDir);
    c.add(bStart);
    
    lBall.setBounds(790,60,20,20);
    lTitTema.setBounds(30,35,790,25);
    lBaixo.setBounds(30,400,790,10);
    lEsq.setBounds(30,60,10,340);
    lDir.setBounds(810,60,10,340);
    
    lRaq.setBounds(40,195,20,70);
    lPts.setBounds(365,420,65,25);
    lExPts.setBounds(435,420,40,25);

    bStart.setBounds(30,420,70,25);
    bStart.addActionListener(this);
    bStop.setBounds(30,420,70,25);
    bStop.addActionListener(this);
    bReset.setBounds(670,420,70,25);
    bReset.addActionListener(this);
    bSair.setBounds(750,420,70,25);
    bSair.addActionListener(this);
    
    lRaqY = lRaq.getY();
    lRaqX = lRaq.getX();
    
    lBallY = lBall.getY();
    lBallX = lBall.getX();
    
    setSize(865,500);
	  setVisible(true);
	  setResizable(true);
    //setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
	  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  }

  //--------------------------------------------------------------------------------------------------------------------------------------
  // ACTION PERFORMED
  //--------------------------------------------------------------------------------------------------------------------------------------
  public static void main(String args[]) {
    Pinball pb = new Pinball();
  }
  
  public void actionPerformed(ActionEvent evt) {
    // START
    if (evt.getSource() == bStart) {
      bStart.setEnabled(false);
      max = 380; 
      min = 60;
      num_Al = min + (int)(Math.random() * (max - min)); 
      movBall_Down();
    }
    
    //-------------------------------------------------------------------------------------------------------------------------
    // RESET
    if (evt.getSource() == bReset) {
      lBall.setBounds(790,60,20,20);
      bStart.setEnabled(true);
    }
    
    //-------------------------------------------------------------------------------------------------------------------------
    // STOP
    if (evt.getSource() == bStop) {
      bStart.setVisible(true);
      bStop.setVisible(false);
    }
    
    //--------------------------------------------------------------------------------------------------------------------------------------
    // SAIR
    //--------------------------------------------------------------------------------------------------------------------------------------
    if (evt.getSource() == bSair) {
      // passando this e nao null, mensagem aparece centro da janela
      int selectedOption = JOptionPane.showConfirmDialog(this, "Deseja Sair Realmente?", "Atencao", JOptionPane.YES_NO_OPTION);
      
      if (selectedOption == JOptionPane.YES_OPTION) {
        dispose();
        //System.exit(0);
      }
    }
  } // fim Action Performed
    
  //--------------------------------------------------------------------------------------------------------------------------------------
  // FUNCOES
  //--------------------------------------------------------------------------------------------------------------------------------------
  
  //--------- movRaqUp() ---------------
  public static void movRaqUp() {
    RunMovRaq_Up u = new RunMovRaq_Up(60);
    Thread mu = new Thread(u);
    mu.start();
  }
  //--------- movRaqDown() ---------------
  public static void movRaqDown() {
    RunMovRaq_Down d = new RunMovRaq_Down(330);
    Thread md = new Thread(d);
    md.start();
  }

  //--------- movRaqRight_01() ---------------
  public static void movRaqRight_01() {   
    RunMovRaq_Right_01 r1 = new RunMovRaq_Right_01();
    Thread mr1 = new Thread(r1);
    mr1.start();
  }

  //--------- movBall_Down() ---------------
  public static void movBall_Down() {   
    RunMovBall_Down mb = new RunMovBall_Down();
    Thread mbd = new Thread(mb);
    mbd.start();
  }
  
  //--------- movBall_Left() ---------------
  public static void movBall_Left() {   
    RunMovBall_Left mvb = new RunMovBall_Left();
    Thread mbl = new Thread(mvb);
    mbl.start();
  }
  
  //--------- verif_col() ---------------
  public static void verif_col() { 
    if (lBall.getX() <= (lRaq.getX() + 20) && lBall.getY() <= (lRaq.getY() + 70) && (lBall.getY() + 20) >= lRaq.getY()) {
      stop_mov();
    }
  }
  
  //--------- stop_mov() ---------------
  public static void stop_mov() {       	            	     
    RunMovBall_Left.contInicial = 39;              	            	 
  }
  
  //-------------------------------------------------------------------------------------------------------------------------------------
  
  public void keyPressed(KeyEvent e) {
    int codigo = e.getKeyCode();
    
    //------------------------------------------- p/ RAQ BAIXO --------------------------------------------
    if (e.getKeyCode() == 40) {
      movRaqDown();
    }
    
    //------------------------------------------- p/ RAQ DIREITA ------------------------------------------
    if (e.getKeyCode() == 39) {
      movRaqRight_01();
    }
    
    //--------------------------------------------- p/ RAQ CIMA -------------------------------------------
    if (e.getKeyCode() == 38) {
      movRaqUp();
    }
    
    //-------------------------------------------------------------------------------------------------
  }
  
  public void keyReleased(KeyEvent e) {
    if (e.getKeyCode() == 39) {
      // uma tecla foi solta
      lRaq.setBounds(40, lRaq.getY(), 20, 70);
    }
  }
  
  public void keyTyped(KeyEvent e) {
    // uma tecla foi pressionada
  }
  
  @Override
  public void focusGained(FocusEvent arg0) {
    // TODO Auto-generated method stub				
  }
  
  @Override
  public void focusLost(FocusEvent arg0) {
    // TODO Auto-generated method stub
  }
  
  @Override
  public void itemStateChanged(ItemEvent arg0) {
    // TODO Auto-generated method stub
  }
}
package Run_;

public class RunMovRaq_Right_01 implements java.lang.Runnable {

  // �rea de dados da Thread
  public static int contMov;
  // public static int flag=0;
  public static int limite = 30;
  
  // inicializador da MinhaThread
  public RunMovRaq_Right_01() {
    this.limite = limite; // enviando limite = 0
  }
  
  public void run() {
    if (limite > 0) {
      Pinball.lRaqX = Pinball.lRaqX + 2;
      Pinball.lRaq.setBounds(Pinball.lRaqX, Pinball.lRaqY, 20, 70);
      limite--;
      
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace(System.err);
      }
    } else {
      limite = 30;
      Pinball.lRaqX = 40;
      Pinball.lRaq.setBounds(40, Pinball.lRaqY, 20, 70);
    }
  }
  
  public static void start() {
    RunMovRaq_Right_01.start();
  }
}
package Run_;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.io.*;

public class RunMovRaq_Up implements java.lang.Runnable {
  // �rea de dados da Thread
  public static int contMov;
  // public static int flag=0;
  public static int limite;
  
  // inicializador da MinhaThread
  public RunMovRaq_Up(int limite) // limite = 60
  {
    this.limite = limite;
    limite = 60;
    this.contMov = contMov;
    contMov = Pinball.lRaq.getY();
  }
  
  public void run() {
    if (contMov > limite) {
      Pinball.lRaqY = Pinball.lRaqY - 5;
      Pinball.lRaq.setBounds(40, Pinball.lRaqY, 20, 70);
      
      try {
        Thread.sleep(0);
      } catch (InterruptedException e) {
        e.printStackTrace( System.err );
      }
    }
  }
  
  public static void start() {
    RunMovRaq_Up.start();
  }
}
package Run_;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.io.*;

public class RunMovRaq_Down implements java.lang.Runnable {
  // �rea de dados da Thread
  public static int contMov;
  // public static int flag=0;
  public static int limite;
  
  // inicializador da MinhaThread
  public RunMovRaq_Down(int limite) {
    this.limite = limite;
    limite = 330;
    this.contMov = contMov;
    contMov = Pinball.lRaq.getY();
  }
  
  public void run() {
    if (contMov < limite) {   	              
      Pinball.lRaqY = Pinball.lRaqY + 5;
      Pinball.lRaq.setBounds(40, Pinball.lRaqY, 20, 70);
      
      try {
        Thread.sleep(0);
      } catch (InterruptedException e) {
        e.printStackTrace(System.err);
      }
    }
  }
  
  public static void start() {
    RunMovRaq_Down.start();
  }
}
package Run_;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.io.*;

public class RunMovBall_Down implements java.lang.Runnable {

  // �rea de dados da Thread
  public static int contInic;
  // public static int flag=0;
  public static int limite, pt;
  
  // inicializador da MinhaThread
  public RunMovBall_Down() {
    this.limite = Pinball.num_Al;
    this.contInic = 60;
  }
  
  public void run() {    	 
    if (contInic <= limite) {         
      while (contInic <= limite) {
        Pinball.lBall.setBounds(790, contInic, 20, 20);
        contInic++;
        
        try {
          Thread.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace(System.err);
        }
      }
    }
    
    Pinball.movBall_Left();
  }
  
  public static void start() {
    RunMovBall_Down.start();
  }
}
package Run_;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.applet.*;
import java.io.*;

public class RunMovBall_Left implements java.lang.Runnable {

  // �rea de dados da Thread
  public static int contInicial;
  // public static int flag=0;
  public static int limite;
  
  // inicializador da MinhaThread
  public RunMovBall_Left() {
    this.limite = limite;
    this.contInicial = 790;
  }
  
  public void run() {
    if (contInicial > 40) {
      while (contInicial >= 40) {
        Pinball.lBall.setBounds(contInicial, Pinball.num_Al, 20, 20);
        contInicial--;
        Pinball.verif_col();
        
        try {
          Thread.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace(System.err);
        }
      }
    } else {
      Pinball.lBall.setBounds(790, contInicial, 20, 20);
    }
  }
  
  public static void start() {
    RunMovBall_Left.start();
  }
}

Por que é que é tudo static?
Por que cada movimento dispara uma nova Thread?

Entao, staroski, eu estou meio perdido e queria achar o caminho para poder fazer uma ‘raquete’ se mover, durante o movimento de uma ‘bola’. Só que enquanto a ‘bola’ está se movendo, não consigo fazer a ‘raquete’ se mover. Enquanto uma thread está em execução a outra não funciona. Eu fiz como imaginei e achei que ia funcionar. Não funcionou. O que eu tenho que mudar?

Tudo sendo static (como já apontado pelo Staroski) vai atrapalhar seu programa (as threads vão competir em um monte de recursos) e o seu loop dorme apenas um millisegundo, o que não da nem tempo de algo ser redenizado, e já terá outra thread movendo-o do lugar. Repare que um monitor tem 60 frames por segundo e você está tentando mover mil vezes a cada segundo. Isso vai travar sua app.

Não se sai criando uma Thread pra cada operação.
Pesquise sobre como implementar um Game Loop, é a melhor alternativa para fazer o que você quer.
Um Game Loop é uma única Thread que basicamente repete um laço com as seguintes operações:

  • recebe a entrada de dados do usuário;
  • atualiza o estado de todos os objetos;
  • renderiza a cena.
1 curtida

Obrigado pela dica, staroski. Vou tentar isso. Depois posto aqui os resultados. Obrigado