Results 1 to 8 of 8
  1. #1
    Ypsilon IV is offline Member
    Join Date
    Apr 2009
    Location
    Earth
    Posts
    14
    Rep Power
    0

    Default [SOLVED] Method from one thread called on another thread

    Hi everyone! My code below is a bouncing balls application. I have use a tip "How to create a bouncing ball animation" from this forum as a base. When I click "New ball" button new ball appears on the screen and new thread is starded. Still I don't get couple of things (this is my first such thread exprerience) and would like to ask for help:
    When there are two or more balls on the screen I would like to be able to call collide() method from MovingBall class, so that objects (balls) may change their trajectory of motion on the screen. How do I do it? Should I try something like this?
    1. Create a MovingBall array
    2. When "New ball" button is clicked new element is added
    3. The in a loop I go though all elements in this array and call collide() method for every other element

    But I have a problem with implementing this idea (How do I add elements to an array dynamically? Will such method call
    Java Code:
    BallArray[i].collide(BallArray[i+1])
    work?)

    I would appreciate very much any piece of advice, please help a beginner! Thanks in advance!

    P.S. Here's the code (I use Eclipse Europa, so each class is in a separate file):
    Java Code:
    package modification;
    
    import java.awt.*;
    import java.lang.*;
    import javax.swing.*;
    
    public class Ball extends Thread{
    	public Ball (double x, double y, double r, Color c, JPanel b) {
    		this.X = x;
    		this.Y = y;
    		this.Radius = r;
    		this.Colour = c;
    		this.box = b;
    	}
    	
    	public void paint () {
    		Graphics g = box.getGraphics();
    		g.setColor(Colour);
    		g.fillOval((int)(X - Radius), (int)(Y - Radius), (int)(2*Radius), (int)(2*Radius));
    		g.dispose();
    	}
    	
    	protected double X;
    	protected double Y;
    	protected double Radius;
    	protected Color Colour;
    	protected JPanel box;
    }
    Java Code:
    package modification;
    
    import java.awt.*;
    import java.lang.*;
    import javax.swing.*;
    
    public class MovableBall extends Ball{
    	public MovableBall(double x, double y, double r, double s, double a, double g, Color c, JPanel b) {
    		super(x, y, r, c, b);
    		this.Angle = Math.toRadians(a);
    		this.Speed = s;
    		this.Gravity = g;
    	}
    	
    	private double getSpeedX() {
    		return Speed * Math.cos(Angle);	
    	}
    	
    	private double getSpeedY() {
    		return Speed * Math.sin(Angle);
    	}
    	
    	public void run() {
    		try {
    			paint();
    			for (int i = 1; i <= 10000; i++) {
    				move();
    				sleep(20);
    			}
    		}
    		catch (InterruptedException e) {
    			
    		}
    	}
    	
    	public void move() {
    		if(!box.isVisible())
    			return;
    		
    		Graphics g = box.getGraphics();
    	    g.setXORMode(box.getBackground());
    	    g.setColor(Colour);
    	    g.fillOval((int)(X - Radius), (int)(Y - Radius), (int)(2*Radius), (int)(2*Radius));
    		
    		X += getSpeedX(); Y += getSpeedY();
    		
    		Dimension Size = box.getSize();
    		
    		if((X < Radius) && (Y< Radius)) {
    			Angle = (((Math.PI) - Math.abs(Angle)))*(-1);
    			Speed = - Speed;
    		}
    		
    		if((X < Radius) || X > (Size.width - Radius)) {
    
    			if(Angle < 0) {
    				Angle = (((Math.PI) - Math.abs(Angle)))*(-1);
    			}
    			else {
    				Angle = (((Math.PI) + Math.abs(Angle)))*(-1);
    			}
    		}
    		
    		if((Y < Radius) || Y > (Size.height - Radius)) {
    
    			if(Angle < 0) {
    				Angle = (((Math.PI/2) + Math.abs(Angle)))*(-1);
    			}
    			else {
    				Angle = (((Math.PI/2) - Math.abs(Angle)))*(-1);
    			}
    		}
    		
    		g.fillOval((int)(X - Radius), (int)(Y - Radius), (int)(2*Radius), (int)(2*Radius));
    		g.dispose();
    	}
    	
    	public boolean Collide(MovableBall Target) {
    		
    		double dX, dY;
    		
    		if (this.X > Target.X)
    			dX = this.X - Target.X - 1;
    		else
    			dX = Target.X - this.X - 1;
    		if (this.Y > Target.Y)
    			dY = this.Y - Target.Y - 1;
    		else
    			dY = Target.Y - this.Y - 1;
    		
    		int Distance = (int)Math.sqrt(dX * dX + dY * dY);
    		
    		if (Distance > (int)(this.Radius + Target.Radius))
    			return false;
    		
    		double Alpha = Math.atan2(dY, dX);
    		
    		double v1X = this.Speed * Math.cos(Alpha - this.Angle);
    		double v1Y = this.Speed * Math.sin(Alpha - this.Angle);
    		double v2X = Target.Speed * Math.cos(Alpha - Target.Angle);
    		double v2Y = Target.Speed * Math.sin(Alpha - Target.Angle);
    		
    		double v3X = ((this.Radius - Target.Radius) * v1X + 2.0 * Target.Radius * v2X) / (this.Radius + Target.Radius);
    	    double v4X = (2.0 * this.Radius * v1X + (Target.Radius - this.Radius) * v2X) / (this.Radius + Target.Radius);
    	    double v3Y = ((this.Radius - Target.Radius) * v1Y + 2.0 * Target.Radius * v2Y) / (this.Radius + Target.Radius);
    	    double v4Y = (2.0 * this.Radius * v1X + (Target.Radius - this.Radius) * v2Y) / (this.Radius + Target.Radius); 
    	    
    	    this.Speed = Math.sqrt(v3X * v3X + v3Y * v3Y);
    	    Target.Speed = Math.sqrt(v4X * v4X + v4Y * v4Y);
    	    
    	    this.Angle = Alpha - Math.atan2(v3Y, v3X);
    	    Target.Angle = Alpha - Math.atan2(v4Y, v4X);
    	    
    	    return true;
    	}
    	
    	private double Gravity;
    	private double Angle;
    	private double Speed;
    }
    Java Code:
    package modification;
    
    import java.awt.*;
    import java.awt.event.*;
    
    import javax.swing.*;
    
    public class BouncingBallThreadFrame extends JFrame {
    	  public BouncingBallThreadFrame() {
    		  setSize(600, 500);
    		  setTitle("Bounce");
    		  
    		  addWindowListener(new WindowAdapter() {
    			  public void windowClosing(WindowEvent e) {
    				  System.exit(0);
    				  }
    			  });
    
    		  Container contentPane = getContentPane();
    		  canvas = new JPanel();
    		  contentPane.add(canvas, "Center");
    		  JPanel p = new JPanel();
    		  addButton(p, "Start", new ActionListener() {
    			  public void actionPerformed(ActionEvent evt) {
    // public MovableBall(double x, double y, double r, double s, double a, double g, Color c, JPanel b
    				  MovableBall b1 = new MovableBall(120, 60, 25, 4, 20, 0, Color.red, canvas);
    				  b1.start();
    				//  b1.Collide(b2); how to i call this method here?
    				  }
    			  });
    
    		  addButton(p, "Close", new ActionListener() {
    			  public void actionPerformed(ActionEvent evt) {
    				  canvas.setVisible(false);
    				  System.exit(0);
    				  }
    			  });
    		  contentPane.add(p, "South");
    	  }
    	  
    	  public void addButton(Container c, String title, ActionListener a) {
    		  JButton b = new JButton(title);
    		  c.add(b);
    		  b.addActionListener(a);
    	  }
    	  
    	  private JPanel canvas;
    }
    Java Code:
    package modification;
    
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class BouncingBallThread {
    	  public static void main(String[] args) {
    		    JFrame frame = new BouncingBallThreadFrame();
    		    frame.show();
    	  }
    }
    Last edited by Ypsilon IV; 04-24-2009 at 02:08 PM.

  2. #2
    OrangeDog's Avatar
    OrangeDog is offline Senior Member
    Join Date
    Jan 2009
    Location
    Cambridge, UK
    Posts
    838
    Rep Power
    11

    Default

    That should work. You might find that using a Collection would be easier than using an array, some kind of List is probably what you want.
    Don't forget to mark threads as [SOLVED] and give reps to helpful posts.
    How To Ask Questions The Smart Way

  3. #3
    Ypsilon IV is offline Member
    Join Date
    Apr 2009
    Location
    Earth
    Posts
    14
    Rep Power
    0

    Default

    Thanks for reply!
    I have modified the code a bit, so that i use Vector of MovableBalls. So I go through the vector and call collide() method. However, doesn't seem to work in the way I've implemented - ball just seem to fly through each other, though they should collide and go different ways.
    Could you please give me a hint, where the error can be?
    I modified just on class, I have marked the changes as "code added here":
    Java Code:
    package modification;
    
    import java.awt.*;
    import java.awt.event.*;
    import java.util.*;
    
    import javax.swing.*;
    
    public class BouncingBallThreadFrame extends JFrame {
    	  public BouncingBallThreadFrame() {
    		  setSize(600, 500);
    		  setTitle("Bounce");
    		  
    		  addWindowListener(new WindowAdapter() {
    			  public void windowClosing(WindowEvent e) {
    				  System.exit(0);
    				  }
    			  });
    
    		  Container contentPane = getContentPane();
    		  canvas = new JPanel();
    		  contentPane.add(canvas, "Center");
    		  JPanel p = new JPanel();
    		  addButton(p, "Start", new ActionListener() {
    			  public void actionPerformed(ActionEvent evt) {
    				  MovableBall b1 = new MovableBall(50, 100, 25, 4, 20, 0, Color.red, canvas);
    				  BallVector.add(b1);
    				  b1.start();
    // code added here
    				  for(int i = 0; i < BallVector.size() - 1; i ++) {
    					  BallVector.elementAt(i).Collide(BallVector.elementAt(i+1));
    				  }
    				  
    			  }
    		  });
    
    		  addButton(p, "Close", new ActionListener() {
    			  public void actionPerformed(ActionEvent evt) {
    				  canvas.setVisible(false);
    				  System.exit(0);
    				  }
    			  });
    		  contentPane.add(p, "South");
    	  }
    	  
    	  public void addButton(Container c, String title, ActionListener a) {
    		  JButton b = new JButton(title);
    		  c.add(b);
    		  b.addActionListener(a);
    	  }
    	  // code added here
    	  Vector<MovableBall> BallVector = new Vector<MovableBall>();
    	  private JPanel canvas;
    }

  4. #4
    OrangeDog's Avatar
    OrangeDog is offline Senior Member
    Join Date
    Jan 2009
    Location
    Cambridge, UK
    Posts
    838
    Rep Power
    11

    Default

    You are aware that collide() doesn't make the balls collide? It just returns true if they are within the collision radius.

    Also, to iterate through a Vector, you can use a for-each loop
    Java Code:
    for (MoveableBall b : BallVector) {
    }
    Don't forget to mark threads as [SOLVED] and give reps to helpful posts.
    How To Ask Questions The Smart Way

  5. #5
    Ypsilon IV is offline Member
    Join Date
    Apr 2009
    Location
    Earth
    Posts
    14
    Rep Power
    0

    Default

    Thanks! Something has improved, but still.. I have a mental block at some point:
    I have modified Collide() to be void, so it is supposed to to its job "quetly". But how can I get out of Collide() if distance is greater? I have placed "return" statement in "if" clause (I've marked it in the code"), but still nothing happens. I've added some "print" statement to console - just to trace if I get there, but no message appears, not collision appears. However, I've tried to comment the lines
    Java Code:
    		if (Distance > (int)(this.Radius + Target.Radius))
    			return;
    - after that, when new ball appears - "collider" works! But, of course, every movement is considered to be collision, so even new appearing balls start changing their speeds and trajectories. How can I fix that?

    P.S. Thank for advice about foreach-type loop!
    Java Code:
    public void Collide(MovableBall Target) {
    		
    		double dX, dY;
    		
    		if (this.X > Target.X)
    			dX = this.X - Target.X - 1;
    		else
    			dX = Target.X - this.X - 1;
    		if (this.Y > Target.Y)
    			dY = this.Y - Target.Y - 1;
    		else
    			dY = Target.Y - this.Y - 1;
    		
    		int Distance = (int)Math.sqrt(dX * dX + dY * dY);
    		// how to resolve this?
    		if (Distance > (int)(this.Radius + Target.Radius))
    			return;
    		System.out.print("got down here!");
    		double Alpha = Math.atan2(dY, dX);
    		
    		double v1X = this.Speed * Math.cos(Alpha - this.Angle);
    		double v1Y = this.Speed * Math.sin(Alpha - this.Angle);
    		double v2X = Target.Speed * Math.cos(Alpha - Target.Angle);
    		double v2Y = Target.Speed * Math.sin(Alpha - Target.Angle);
    		
    		double v3X = ((this.Radius - Target.Radius) * v1X + 2.0 * Target.Radius * v2X) / (this.Radius + Target.Radius);
    	    double v4X = (2.0 * this.Radius * v1X + (Target.Radius - this.Radius) * v2X) / (this.Radius + Target.Radius);
    	    double v3Y = ((this.Radius - Target.Radius) * v1Y + 2.0 * Target.Radius * v2Y) / (this.Radius + Target.Radius);
    	    double v4Y = (2.0 * this.Radius * v1X + (Target.Radius - this.Radius) * v2Y) / (this.Radius + Target.Radius); 
    	    
    	    this.Speed = Math.sqrt(v3X * v3X + v3Y * v3Y);
    	    Target.Speed = Math.sqrt(v4X * v4X + v4Y * v4Y);
    	    
    	    this.Angle = Alpha - Math.atan2(v3Y, v3X);
    	    Target.Angle = Alpha - Math.atan2(v4Y, v4X);
           }
    Last edited by Ypsilon IV; 04-24-2009 at 03:48 AM.

  6. #6
    Ypsilon IV is offline Member
    Join Date
    Apr 2009
    Location
    Earth
    Posts
    14
    Rep Power
    0

    Default

    Ah, I understood an error!
    I've done the following: I've added one more "print" statement in collide() to show current distance between objects:
    Java Code:
    		int Distance = (int)Math.sqrt(dX * dX + dY * dY);
    		System.out.print(Distance);
    		if (Distance > (int)(this.Radius + Target.Radius))
    			return;
    		System.out.print("got down here!");
    But here
    Java Code:
    				  for(int i = 0; i < BallVector.size() - 1; i ++) {
    					  BallVector.elementAt(i).Collide(BallVector.elementAt(i+1));
    				  }
    I check distance only once, during creation of a new ball! This was totaly unexpected, I would like to check the distances constantly, how can I achieve that?:
    • I cannot simply put collide() check to move() method, as in move no instance of other ball is known
    • And I don't understand how I can check constantly from outer class, BouncingBallThreadFrame

    What could you please advise me?

  7. #7
    OrangeDog's Avatar
    OrangeDog is offline Senior Member
    Join Date
    Jan 2009
    Location
    Cambridge, UK
    Posts
    838
    Rep Power
    11

    Default

    You need to add a field to your ball class, and pass the BallVector in the constructor. This way every ball instance will have a reference to the list of all other balls, allowing you to check in the move() method whether balls have collided.

    Don't forget that a ball will always say it has collided with itself.
    Don't forget to mark threads as [SOLVED] and give reps to helpful posts.
    How To Ask Questions The Smart Way

  8. #8
    Ypsilon IV is offline Member
    Join Date
    Apr 2009
    Location
    Earth
    Posts
    14
    Rep Power
    0

    Default

    Thank you very very much! I've modified the code and it works now! Thanks a lot!

Similar Threads

  1. Difference between Thread.yield() and Thread.sleep() methods
    By Nageswara Rao Mothukuri in forum New To Java
    Replies: 12
    Last Post: 07-30-2010, 05:37 PM
  2. passing a value from parent thread to child thread
    By sachinj13 in forum Threads and Synchronization
    Replies: 7
    Last Post: 09-07-2008, 09:06 PM
  3. data from the main/GUI thread to another runnin thread...
    By cornercuttin in forum Threads and Synchronization
    Replies: 2
    Last Post: 04-23-2008, 10:30 PM
  4. Replies: 0
    Last Post: 01-28-2008, 07:02 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •