Author Topic: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?  (Read 18078 times)

chuks

  • Newbie
  • *
  • Posts: 27
  • Karma: 0
    • View Profile
Buenas.

Estoy practicando con un sencillo programa de dos bolas que rebotan pero no me sale lo que quiero.

Como puedo hacer en el metodo paintComponent que dependiendo del hilo asociado a cada bola, me pinte una bola u otra?

 La finalidad es que me dibuje las dos bolas cada una a diferente velocidad (La que marca el retardo de cada hilo).

Seguro que habra mejores formas que la que planteo para hacer el ejercicio pero es para aprender.

He aqui los progresos:

Code: [Select]

import java.awt.Color;
import javax.swing.JFrame;

public class Muevepelota extends JFrame {
   
    public static void main(String[] args) {       
        Muevepelota f = new Muevepelota();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(new PanelPelota());
        f.setSize(450, 500);
        f.setVisible(true);
    }
}


import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;

public class PanelPelota extends JPanel implements Runnable{

Thread[] animabola;
Pelota[] p;


public PanelPelota(){
          animabola = new Thread[2]; //Creo dos hilos
          animabola[0]= new Thread(this);
          animabola[1]= new Thread(this);   
          p = new Pelota[2];     //Creo un array con dos bolas.
          p[0]= new Pelota(60,60,1,2,2,Color.red); // 20 velocidad del hilo
          p[1]= new Pelota(20,20,1,1,100,Color.blue); //100 velcidad del hilo
         
          for (int i=0; i<animabola.length; ++i) //Comenzamos cada hilo.
             animabola[i].start();   
}


public void run(){
      while (animabola[0].currentThread()== animabola[0]) {
             try {
                animabola[0].sleep(p[0].retardo()); // Espera 50ms
             }catch (InterruptedException e) { }           
            repaint();
        }
     
      while (animabola[1].currentThread()== animabola[1]) {
             try {
                animabola[1].sleep(p[1].retardo()); // Espera 50ms
             }catch (InterruptedException e) { }
          repaint();           
        }           
      }

 

  public void paintComponent(Graphics g) {       
      super.paintComponent(g); 
       //aqui quiero que si el hilo es el correspondiente a animabola[0] me pinte la bola p[0] y si es animabola[1] me pinte p[1].
        p[0].pintar(g);
       
    }
   
  }



import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

public class Pelota {   
    private int x, y;
    private int dsx, dsy, t; //dsx y dsy son los desplazamientos, t el retardo de la bola
    private int radio = 5; //radio de la bola
    private Color c;   
     
      public Pelota(int x, int y, int dsx, int dsy, int t, Color c ){           
          this.x=x;
          this.y=y;
          this.dsx= dsx;
          this.dsy=dsy;
          this.t=t;
          this.c = c;
      }
     
      public int retardo (){ //retardo de la bola
          return t;
      }
     
      public void pintar (Graphics g){         
        x=x + dsx;
        y=y + dsy;
      // comprueba si choca contra los bordes
        if ( x>= 450-radio || x<= radio)     
            dsx = -dsx;
        if ( y >= 500- radio || y<=radio )
           dsy = -dsy;               
     // pinta la pelota
      g.setColor(c);
      g.fillOval(x-radio, y-radio, radio*4, radio*4);
   //   return g;
      }
   
   
}


Gracias chudiang.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 5473
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #1 on: Octubre 30, 2012, 11:11:53 am »
Hola:

paintComponent debe dibujar todo, no puedes pintar unas cosas sí y otras no.

Debes guardar las coordenadas de cada bola en variables (p[0] y p[1] en tu ejemplo). Tus hilos deben modificar las variables, un hilo las de una bola, el otro hilo las de la otra. Después de modificar las variables, hay que llamar a repaint (o paintComponent). Puedes hacer que cada hilo llame a paintComponents() cada vez que modifique las coordenadas, o bien un tercer hilo encargado de llamar a paintComponents() cada cierto tiempo.

Se bueno.

chuks

  • Newbie
  • *
  • Posts: 27
  • Karma: 0
    • View Profile
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #2 on: Octubre 30, 2012, 05:49:33 pm »
Buenas tardes.

Lo que propones lo intenté y tampoco sale porque el metodo paintComponent, luego llama a pintar() de la clase Pelota y para ello hay que pasarle cada objeto pelota para que la pinte.

En modificar las variables de cada pelota en cada hilo te refieres por ejemplo a esto?

Code: [Select]

public void run(){
      while (animabola[0].currentThread()== animabola[0]) {
             try {
                animabola[0].sleep(p[0].retardo()); // Espera 50ms
             }catch (InterruptedException e) { }           
            p[0].moverbola();
        }
     
      while (animabola[1].currentThread()== animabola[1]) {
             try {
                animabola[1].sleep(p[1].retardo()); // Espera 50ms
             }catch (InterruptedException e) { }
          p[1].moverbola();           
        }           
      }

 


  public void paintComponent(Graphics g) {       
      super.paintComponent(g);
       //Como llamar al metodo pintar en cada pelota?
    }
   


y en la clase Pelota:

Code: [Select]

public void moverbola(){
        x=x + dsx;
        y=y + dsy;
      // comprueba si choca contra los bordes
        if ( x>= 450-radio || x<= radio)     
            dsx = -dsx;
        if ( y >= 500- radio || y<=radio )
           dsy = -dsy;   
       
           //llamar a repaint() de panel pelota.?
         new PanelPelota().repaint();
      }
     
      public void pintar (Graphics g){       
     // pinta la pelota
      g.setColor(c);
      g.fillOval(x-radio, y-radio, radio*4, radio*4);
   //   return g;
      }


Pero estamos en las mismas porque el metodo panitComponent como bien dices lo pinta todo.


chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 5473
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #3 on: Octubre 30, 2012, 07:33:35 pm »
Hola:

La idea sería esta

Code: [Select]
public class UnaClase extends JComponent // o el componente que uses para dibujar
{
    private bola1 = new ...
    private bola2 = new ....

    public void paint(Graphics g) {
          g.draw(bola1);
          g.draw(bola2)
          /// o bien bola1.pintar(g); bola2.pintar(g); según lo tengas.
    }
}

Tus hilos tendrían que tocar las coordendas de unaClase.bola1 y unaClase.bola2 y llamar luego a unaClase.repaint(). El método repaint() de java se encarga de llamar a paint, paintComponents, etc.

El motivo es que la forma fácil de dibujo es dibujarlo todo (es lo que hace java en su método paint()). Si no fuera así, además de pintar la bola en su nueva posición, tendrías que borrarla de la antigua posición, restaurando lo que hubiera de fondo.

Se bueno.

chuks

  • Newbie
  • *
  • Posts: 27
  • Karma: 0
    • View Profile
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #4 on: Octubre 31, 2012, 12:59:21 am »
Buenas,

A ver, las dos bolas las mueve bien el programa, en eso no hay problema. Si pongo lo siguiente:

Code: [Select]
public void paintComponent(Graphics g) {       
      super.paintComponent(g); 
        p[1].pintar(g);
        p[0].pintar(g);
       
    }

Se dibujan las dos bolas y se mueven sin problema. Igual es que no me explico bien. Lo que quier es que una bola se mueva mas rapido que la otra dependiendo de el retardo que ponga en cada uno de los hilos por separado.

Seria tan sencillo como poner algo asi, pero no me funciona:

Code: [Select]
public void paintComponent(Graphics g) {       
      super.paintComponent(g); 
       if (animabola[0].currentThread()== animabola[0])
            p[0].pintar(g);
       if  (animabola[1].currentThread()== animabola[1])
        p[1].pintar(g);
    }

Es decir, una sentencia dentro del paintComponent que discrimine que si estoy en el hilo1 me pinte la bola1 con un retardo que viene dado en la instancia del objeto p[0].  y si se trata del otro hilo, que la mueva con el otro retardo.


NO hay forma de poner nada parecido dentro del paintComponent? seria lo mas sencillo y funcionaria. Lo demas lo he probado todo y no hay manera.

Lo que comentas tambien lo hice y no va.

Saludos y perdon por las molestias.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 5473
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #5 on: Octubre 31, 2012, 01:56:43 am »
Hola:

No, no hay forma de pintar en direferido con el paintComponent ni ningún otro método de java. Esos métodos pintan todo el compoente, salvo que hagas lo que te comente : borrar la posición antigua (dibujando una bola del color de fondo) y luego una nueva.

Si quieres que una corra más que la otra, lo único que tienes que hacer es que los retardo de cada pelota sean distintos, así el hilo con menos retardo actualizará su pelota con más frecuencia y la verás correr más rápido, aunque el pintado pinte las dos cada vez. Si uno tiene un retardo el doble que el otro, la secuencia sería más o meonos así

se incrementa posición de pelota 1 y se repinta todo
se incrementa posición de pelota 1 y se repinta todo
se incrementa posición de pelota 2 y se repinta todo
se incrementa posición de pelota 1 y se repinta todo
se incrementa posición de pelota 1 y se repinta todo
se incrementa posición de pelota 2 y se repinta todo

deberías ver la pelota 1 corriendo el doble de deprisa que la 2, siempre que los incrementos de posición sean iguales (dsx y dsy en tu codigo).

Se bueno.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 5473
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #6 on: Octubre 31, 2012, 02:07:11 am »
Revisando el código con detalle, posiblemente el problema que tienes es que intentas incrementar cuando pintas. Debes incrementar posiciones en el bucle del hilo

Code: [Select]
public void run(){
      while (animabola[0].currentThread()== animabola[0]) {
             try {
                animabola[0].sleep(p[0].retardo()); // Espera 50ms
                // Aqui incrementa posiciones de pelota 0
                // Llama a repaint()
             }catch (InterruptedException e) { }           
            p[0].moverbola();
        }
     
      while (animabola[1].currentThread()== animabola[1]) {
             try {
                animabola[1].sleep(p[1].retardo()); // Espera 50ms
                // Aqui incrementa posiciones de pelota 1
                // Llama a repaint()
             }catch (InterruptedException e) { }
          p[1].moverbola();           
        }           
      }


y en el paint() lo que te comente antes, dibuja ambas pelotas.

Se bueno.

chuks

  • Newbie
  • *
  • Posts: 27
  • Karma: 0
    • View Profile
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #7 on: Octubre 31, 2012, 03:23:21 am »
Hola de nuevo , la velocidad de cada bola la declaro en negrita:

         p[0]= new Pelota(60,60,1,2,2,Color.red); //   2 velocidad del hilo
          p[1]= new Pelota(20,20,1,1,100,Color.blue); //100 velcidad del hilo


cuya velocidad viene determinada por el retraso del hilo:


try {
                animabola[0].sleep(p[0].retardo());


Respecto a lo segundo , te refieres a esto?

Code: [Select]
public void run(){
      while (animabola[0].currentThread()== animabola[0]) {
             try {
                animabola[0].sleep(p[0].retardo()); //
                p[0].moverbola();
                 repaint();             
             }catch (InterruptedException e) { }   

 while (animabola[1].currentThread()== animabola[1]) {
             try {
                animabola[1].sleep(p[1].retardo()); //
                p[1].moverbola();
                repaint();
             }catch (InterruptedException e) { }
                   
        }   


muevo posiciones de p[0] y p[1] mediante el metodo de la clase Pelota creado moverbola():

Code: [Select]
public void moverbola(){
        x=x + dsx;
          y=y + dsy;
      // comprueba si choca contra los bordes
        if ( x>= 450-radio || x<= radio)     
            dsx = -dsx;
        if ( y >= 500- radio || y<=radio )
           dsy = -dsy;   
       

Pero esto no sale porque cuando llamo a repaint este solo puede llamar a pintar() de la clase Pelota.

Code: [Select]
public void paintComponent(Graphics g) {       
      super.paintComponent(g);     
      p[0].pintar(g);
      p[1].pintar(g);

    }

El resultado es que las pinta las dos a la misma velocidad y no a distinta, haz la prueba si quieres.

Igual hay que hacer el metodo del doble buffer porque de esta forma creo que es imposible , al menos no veo como hacerlo.

Gracias.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 5473
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #8 on: Octubre 31, 2012, 05:01:49 am »
Hola de nuevo.

¿Qué tiene pintar()?. Si pintar() no incrementa posiciones y solo dibuja, deberían moverse a distinta velocidad. En los copy paste de atrás tienes dos versiones de pintar, un pintar que solo pinta y un pintar que pinta y mueve. Si pintar() pinta y mueve,

Pon un código completo para que pueda probarlo con copy-paste de un solo bloque.

Se bueno.

chuks

  • Newbie
  • *
  • Posts: 27
  • Karma: 0
    • View Profile
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #9 on: Octubre 31, 2012, 06:59:35 am »
Hola de nuevo chuidiang.   Algo hice mal pero tenias razón, si que funciona. Eres un máquina gracias.

Pongo el código completo:
Code: [Select]
import java.awt.Color;
import javax.swing.JFrame;

public class Muevepelota extends JFrame {
   
    public static void main(String[] args) {       
        Muevepelota f = new Muevepelota();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(new PanelPelota());
       
        f.setSize(450, 500);
        f.setVisible(true);
    }
}

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;

public class PanelPelota extends JPanel implements Runnable{

Thread[] animabola;
Pelota[] p;

public PanelPelota(){
          animabola = new Thread[2]; //Creo dos hilos
          animabola[0]= new Thread(this);
          animabola[1]= new Thread(this);   
          p = new Pelota[2];     //Creo un array con dos bolas.
          p[0]= new Pelota(60,60,1,2,2,Color.red); // 20 velocidad del hilo
          p[1]= new Pelota(20,20,1,1,50,Color.blue); //100 velcidad del hilo
         
          for (int i=0; i<animabola.length; ++i) //Comenzamos cada hilo.
             animabola[i].start();   
}


public void run(){     
    for (int i=0; i<animabola.length; ++i){
      while (animabola[i].currentThread()== animabola[i]) {
             try {
                animabola[i].sleep(p[i].retardo());
                p[i].moverbola();
                 repaint();             
             }catch (InterruptedException e) { } 
        }
    }
}

  public void paintComponent(Graphics g) {       
      super.paintComponent(g);   
      for(int i=0; i<p.length;++i)
         p[i].pintar(g);     
    }
   
  }
 

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;

public class Pelota extends JPanel{   
    private int x, y;
    private int dsx, dsy, t; //dsx y dsy son los desplazamientos, t el retardo de la bola
    private int radio = 5; //radio de la bola
    private Color c;   
 
     
      public Pelota(int x, int y, int dsx, int dsy, int t, Color c ){           
          this.x=x;
          this.y=y;
          this.dsx= dsx;
          this.dsy=dsy;
          this.t=t;
          this.c = c;
      }
     
      public int retardo (){ //retardo de la bola
          return t;
      }
     
      public void moverbola(){
        x=x + dsx;
        y=y + dsy;
      // comprueba si choca contra los bordes
        if ( x>= 450-radio || x<= radio)     
            dsx = -dsx;
        if ( y >= 500- radio || y<=radio )
           dsy = -dsy;   
      }
     
      public void pintar (Graphics g){     
         
     // pinta la pelota
      g.setColor(c);
      g.fillOval(x-radio, y-radio, radio*4, radio*4);
   //   return g;
      }
     
   
}


Un saludo y gracias.

chuks

  • Newbie
  • *
  • Posts: 27
  • Karma: 0
    • View Profile
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #10 on: Octubre 31, 2012, 08:46:20 pm »
Buenos dias, hay una cuestión respecto a las dimensiones del JPanel que no me queda claro.

Cuando pongo las condiciones para que la bola rebote en las paredes, resulta que el panel es mas grande y no se ajusta a lo que yo quiero:

public void moverbola(){
        x=x + dsx;
        y=y + dsy;
      // comprueba si choca contra los bordes
        if ( x>= 450-radio || x<= radio)     
            dsx = -dsx;
        if ( y >= 500- radio || y<=radio )
           dsy = -dsy;   
      }

Si yo previamente he puesto que el Frame tenga unas dimensiones de (450, 500)

 Muevepelota f = new Muevepelota();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(new PanelPelota());       
        f.setSize(450, 500);
        f.setVisible(true);

¿cuales son las dimensiones del JPanel?
¿que tendria que poner en este caso?
 if ( x>= getWidth()-radio || x<= radio)  ,  if ( y >= getHeight()=- radio || y<=radio ) ????



chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 5473
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #11 on: Octubre 31, 2012, 11:09:45 pm »
El JFrame tiene bordes, márgenes y cosas. El JPanel siempre será un poco menor. Consigue los bordes del JPanel con getWidth() y getHeight() de dicho panel. Puedes hacerlo de forma dinámica por si redimensionan la ventana, o una vez al principio una vez que el JFrame ya esté visible con todas "sus cosas" dentro.

Se bueno.

chuks

  • Newbie
  • *
  • Posts: 27
  • Karma: 0
    • View Profile
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #12 on: Noviembre 01, 2012, 12:46:03 am »
Buenas.

Si creo instancias de la clase PanelPelota que extiendo de JPanel:
PanelPelota panel = new PanelPelota();

y trato de sacar la dimension del JPanel desde la clase Pelota por medio de: panel.getWidth() y panel.getHeight()

 if ( x>= panel.getWidth()-radio || x<= radio)     
            dsx = -dsx;
        if ( y >= panel.getHeight()- radio || y<=radio )
           dsy = -dsy;   

el programa se me queda colgado y he re reiniciar el pc.





chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 5473
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #13 on: Noviembre 01, 2012, 02:42:49 am »
¿Reiniciar el PC entero? ¿No solo la aplicación java?

No tienes que crear "instancias" en plural del PanelPelota, sólo tienes que preguntarle el getWidth() y getHeight() del PanelPelota que está visible en pantalla y que has metido en el JFrame.

En vez de

f.setContentPane(new PanelPelota());

haz

panelPelota = new PanelPelota();
f.setContentPane(panelPelota);

donde panelPelota sea un atributo de la clase que tengas accesible (o le pases) a las bolas.

Se bueno.

chuks

  • Newbie
  • *
  • Posts: 27
  • Karma: 0
    • View Profile
Re: Animacion de dos bolas rebotantes. ¿Como asociar cada hilo a cada bola?
« Reply #14 on: Noviembre 24, 2012, 04:14:27 am »
Buenas, he estado ausente unas semanas fuera y vuelvo de nuevo.

Creo que intento hacer lo que me dices pero se sigue quedando colgado el programa. (Netbeans para mas señas).

Lo que hago es crear un atributo panelPelota como dices pero no me sale:

Code: [Select]
public class Pelota {   
    private int x, y;
    private int dsx, dsy, t; //dsx y dsy son los desplazamientos, t el retardo de la bola
    private int radio = 10; //radio de la bola
    private Color c;   
    private PanelPelota panelPelota;
 
     
      public Pelota(int x, int y, int dsx, int dsy, int t, Color c ){           
          this.x=x;
          this.y=y;
          this.dsx= dsx;
          this.dsy=dsy;
          this.t=t;
          this.c = c;
      }
     
      public int retardo (){ //retardo de la bola
          return t;
      }
     
      public void moverbola(){
         
        x=x + dsx;
        y=y + dsy;
      // comprueba si choca contra los bordes
        if ( x>= panelPelota.getWidth()-(radio) || x<= radio)     
            dsx = -dsx;
        if ( y >=panelPelota.getHeight() -(radio) || y<=radio )
           dsy = -dsy;   
      }
     
      public void pintar (Graphics g){     
         
     // pinta la pelota
      g.setColor(c);
      g.fillOval(x-radio, y-radio, radio*2, radio*2);
   //   return g;
      }     
   
}


donde la clase PanelPelota seria:

Code: [Select]
public class PanelPelota extends JPanel implements Runnable{

Thread[] animabola;
Pelota[] p;
PanelPelota panel;

public PanelPelota(){
          animabola = new Thread[2]; //Creo dos hilos
          animabola[0]= new Thread(this);
          animabola[1]= new Thread(this);   
          p = new Pelota[2];     //Creo un array con dos bolas.
          p[0]= new Pelota(60,60,1,2,50,Color.red); // 20 velocidad del hilo
          p[1]= new Pelota(20,20,1,1,2,Color.blue); //100 velcidad del hilo
         
          for (int i=0; i<animabola.length; ++i) //Comenzamos cada hilo.
             animabola[i].start();             
}



public void run(){     
    for (int i=0; i<animabola.length; ++i){
      while (animabola[i].currentThread()== animabola[i]) {
             try {
                animabola[i].sleep(p[i].retardo());
                p[i].moverbola();                           
             }catch (InterruptedException e) { }
             repaint(); 
        }
    }
}

  public void paintComponent(Graphics g) {       
      super.paintComponent(g);   
      for(int i=0; i<p.length;++i)
         p[i].pintar(g);     
    }
   
  }

Se queda colgado.

Gracias de antemano.

 

ey