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 03:08 PM.

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

    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
    6

    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 04: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
    6

    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, 06: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, 10: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, 11:30 PM
  4. Replies: 0
    Last Post: 01-28-2008, 08: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
  •