## coveredinflies

Hi,
Basically I want to simulate lots of circles bouncing off of each other in a box.
My current plan is to form a grid with lots of points and give each particle a position and speed which is a multiple of the grid spacings. Then at each time move the particles and see if any intersect. I am fairly new to programming so this way is easier in that respect but it seems like this way will be very computationally intensive though.

Do you think this is a good way to do it or will I be wasting my time?

Thanks.

P.S I may do it in C++ or java I haven't decided yet if that makes any difference. (I am not sure yet how easy it is to display it graphically in java yet).

## coveredinflies

Thanks, I am not too concerned with the graphics to start with (it is a science thing) that website looks quite useful though.

## dickersonka 104

ahhh, math junkie then lol

this might be helpful as well, more of the logic side, than the graphical

commented: Thanks +1

## BestJewSinceJC 700

If you are simulating lots of circles bouncing off of each other, you would have to compute whether or not they are currently touching/adjacent by giving each circle a radius, and keeping the current position of the circle's center. Then, as the circle bounced, you could do a calculation between it and all the other circles to figure out if the circle is currently occupying space which is touching another circle's space. If so, bounce them in different directions. Thats the only way I can think to do this assignment. It would be much more difficult to treat each circle as having "multiple points" and then try to see if any of the points are touching than to use each circle's current center point as a marker for whether or not it is adjacent to any other circles (based on their center, radius, and area formulas).

## coveredinflies

Thanks you too, giving it a whirl now.

## Ezzaral 2,714

If you haven't already, you may want to look through the Ellipse2D API. It has methods related to containment and intersection that may prove useful.

## coveredinflies

If you haven't already, you may want to look through the Ellipse2D API. It has methods related to containment and intersection that may prove useful.

Thanks, unfortunately I had already started before I read your post but at least I will think to look in the class file next time. Anyway for a first approximation I thought up a simple way to do it so the physics side is coming along nicely :).

Not sure if I should post in the same thread or not but I have (stupidly) decided to try and animate using the ActionListener (I can't figure out the Threads and Runnable stuff, at least not without more time anyway). I have a couple of problems though if someone could point me in the right direction I would be very grateful.

Firstly when I repaint() my blob doesn't come back :'( . Does repaint() simply call the paintcomponent function again? I can't figure out why it isn't working. I pretty much 'stole' the graphics part of my program from the net and my textbook so it might be (hopefully) an obvious problem.

Here is my program with the irrelevant physics taken out.

``````public class Brownain
{
public static void main(String[] args)
{
JFrame box = new JFrame();
Container background = box.getContentPane();
background.setBackground(new Color(255,250,202));
box.setSize(700, 700);
box.setTitle("Browniand Motion.");
box.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Particle particle = new Particle();
box.setVisible(true);

ActionListener listener = new Particle(); Does this mean it doesn't update the particle I made earlier but this 'listener' particle?

Timer mover = new Timer(25, listener);

mover.start();

}

}

class Particle extends JComponent implements ActionListener
{
public Particle()
{
rand = new Random();
xcentre = rand.nextDouble()*600;
ycentre = rand.nextDouble()*600;
System.out.println(xcentre);
particle = new Ellipse2D.Double(xcentre, ycentre, 30, 30);
}

public double getx()
{
return xcentre;

}

public double gety()
{
return ycentre;
}

{
}

public void actionPerformed(ActionEvent event)
{

xcentre+=rand.nextGaussian()*10;
ycentre+=rand.nextGaussian()*10;

repaint();
}

public void paintComponent(Graphics g)
{
super.paintComponent(g);

Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.PINK);

g2.fill(particle);
g2.draw(particle);
}

private double xcentre;
private double ycentre;
private double mass;
private double xvel;
private double yvel;
private Random rand;
private Ellipse2D.Double particle;

}``````

Also eventually I want to have many particles on the screen at once and have all there positions updating with the ActionListener but when I add

``````for(int i=0; i<50; i++)
{
molecule[i] = new Particle();
}``````

Only 1 extra particle appears which I find very strange.

Anyway sorry about the long post hopefully it won't get lost hidden in my old thread and someone can help me out :icon_biggrin:

## dickersonka 104

sorry not able to confirm this and test your code right now, but try adding validate() before your repaint()

## Ezzaral 2,714

>Does this mean it doesn't update the particle I made earlier but this 'listener' particle?
Yes. Add the one that you already created, since that is the one you want the timer to call on.

## Ezzaral 2,714

I just ran the code here. You also need to set 'radius'. It's currently zero. I changed this in your constructor

``````public Particle()
{
rand = new Random();
xcentre = rand.nextDouble()*600;
ycentre = rand.nextDouble()*600;
System.out.println(xcentre);
}``````

and it works fine (assuming you changed the timer listener parameter to 'particle')

## Ezzaral 2,714

I think some slight modifications to your design could make things much easier. You may want to consider something like this as a starting point

``````import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Brownian {

public static void main(String[] args) {
JFrame box = new JFrame();
Container background = box.getContentPane();
background.setBackground(new Color(255, 250, 202));
box.setSize(700, 700);
box.setTitle("Browniand Motion.");
box.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

ParticlePanel particlePanel = new ParticlePanel();
box.setVisible(true);

Timer mover = new Timer(25, particlePanel);

mover.start();

}
}

/** This panel serves as the container for your Particle objects */
class ParticlePanel extends JPanel implements ActionListener {

List<Particle> particles = new ArrayList<Particle>();

public ParticlePanel() {
super();
// this is all you need to add another
}

/** invoked by the Timer callback */
public void actionPerformed(ActionEvent event) {
for (Particle p : particles) {
p.updatePosition();
}
repaint();
}

public void paintComponent(Graphics g) {
// clear the panel
g.clearRect(0, 0, getWidth(), getHeight());
// render each particle
for (Particle p : particles) {
p.render(g);
}
}
}

/** This class now just deals with the specifics of
* a particle itself. It doesn't need to know anything
* about listeners or the container.
*/
class Particle {

public Particle() {
rand = new Random();
// You could pass these as parameters here if you want to
// randomize the location and size when you create them.
// That could be more helpful since this class doesn't really
// have any knowledge of their container at this point.
xcentre = rand.nextDouble() * 600;
ycentre = rand.nextDouble() * 600;
System.out.println(xcentre);
}

public double getx() {
return xcentre;
}

public double gety() {
return ycentre;
}

}

public void updatePosition() {
xcentre += rand.nextGaussian() * 10;
ycentre += rand.nextGaussian() * 10;

// needs radius*2 because the frame is a bounding box
}

public void render(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setPaint(Color.PINK);
g2.fill(particle);
g2.draw(particle);
}

/** checks for collision between this and another Particle */
public boolean collidesWith(Particle p){
// hint: true if distance between centers is less than
// the sum of their radii
return false;
}

/** handles the result of a collision with Particle p */
protected void processCollision(Particle p){

}

private double xcentre;
private double ycentre;
private double mass;
private double xvel;
private double yvel;
private Random rand;
private Ellipse2D.Double particle;
}``````
commented: Thanks very nice of you! +1

## coveredinflies

I think some slight modifications to your design could make things much easier. You may want to consider something like this as a starting point

Thanks a lot, that was way more than I expected, really nice of you!
I think putting the listener in its own class will stop getting me so confused. I don't understand why you have radius*2 on line 83 and 103 though?

Anyway thanks again will go and type away!

## Ezzaral 2,714

The size parameters for Ellipse2D specify the bounding box by width(w) and height(h), thus they are twice the radius of your circle.

## coveredinflies

Hey, I know you have given me lots of help already but I am still having problems. Basically only the particle added when the constructor of particle panel is called shows up on the screen.

(By the way I know the physics isn't working properly yet and it isn't bouncing off walls but once I can see what is happening I can probably sort it out).

``````import java.util.*;
import java.util.List;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import java.awt.geom.*;
import java.awt.Color;
import java.util.Random.*;
import java.applet.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
import java.awt.Container;
import java.lang.Math;
import java.io.*;

public class RanWalk
{
public static void main(String[] args)
{
JFrame box = new JFrame();
Container background = box.getContentPane();
background.setBackground(new Color(223,255,231));
box.setSize(700, 700);
box.setTitle("Brownian Motion.");
box.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Random rand = new Random();

ParticlePanel particlePanel = new ParticlePanel(rand);
box.setVisible(true);

for(int i = 0; i<50; i++)
{

}

Timer mover = new Timer(50, particlePanel); //delta t is 0.05 seconds
mover.start();

/* FileOutputStream out;
PrintStream p;

out = new FileOutputStream("javamotion.csv");
p = new PrintStream( out );

p.println(t + "," + particle.getx() + "," + particle.gety());
p.close();

*/
}

}

class Collisions
{
Collisions() {}

public boolean collisioncheck(Particle m, Particle p)
{

posx = p.getx();
posy = p.gety();
posx2 = m.getx();
posy2 = m.gety();
distance = Math.sqrt((posx-posx2)*(posx-posx2) + (posy-posy2)*(posy-posy2));
if(distance <= 5+20)
{
check = true;
return check;
}
return check;
}

public void conservemomentum(Particle m, Particle p)
{
mass = p.getMass();
mass2 = m.getMass();

xvel = p.getXVel();
yvel = p.getYVel();
xvel2 = m.getXVel();
yvel2 = m.getYVel();

nextxvel = ((mass-mass2)/(mass+mass2))*xvel + (2*mass2/(mass+mass2))*xvel2;
nextyvel = ((mass-mass2)/(mass+mass2))*yvel + (2*mass2/(mass+mass2))*yvel2;

nextxvel2 = ((mass2-mass)/(mass+mass2))*xvel2 + (2*mass/(mass+mass2))*xvel;
nextyvel2 = ((mass2-mass)/(mass+mass2))*yvel2 + (2*mass/(mass+mass2))*yvel;

p.setXVel(nextxvel);
p.setYVel(nextyvel);
m.setXVel(nextxvel2);
m.setYVel(nextyvel2);
}
private double mass;
private double mass2;
private double xvel;
private double yvel;
private double xvel2;
private double yvel2;
private double nextxvel;
private double nextyvel;
private double nextxvel2;
private double nextyvel2;
private double posx;
private double posy;
private double posx2;
private double posy2;
private double distance;
private boolean check = false;

}

class Particle extends JComponent
{

public Particle(double rad, double m, Random r)
{

mass = m;
xcentre = r.nextDouble()*600;
ycentre = r.nextDouble()*600;
xvel = r.nextGaussian()*10;
yvel =r.nextGaussian()*10;

}

public void updateposition(double t)
{
xcentre+= t*xvel;
ycentre+= t*yvel;

if(xcentre < 0) xcentre = -xcentre;
if(xcentre > 700) xcentre = 1400-xcentre;

if(ycentre < 0) xcentre = -xcentre;
if(ycentre > 700) xcentre = 1400-xcentre;
}

public double getx()
{
return xcentre;

}

public double gety()
{
return ycentre;
}

{
}

public double getMass()
{
return mass;
}

public double getXVel()
{
return xvel;
}

public double getYVel()
{
return yvel;
}

public void setXVel(double v)
{
xvel = v;
}

public void setYVel(double v)
{
yvel = v;
}

private double xcentre;
private double ycentre;
private double mass;
private double xvel;
private double yvel;
private Random rand;
private Ellipse2D.Double particle;

}

class ParticlePanel extends JPanel implements ActionListener
{
public double DeltaT = 0.05;

List<Particle> particles = new ArrayList<Particle>();

public ParticlePanel(Random r)
{
super();
}

public void actionPerformed(ActionEvent event)
{
Collisions tool = new Collisions();
boolean collision = false;
for(int i=0; i <51; i++)
{

collision = tool.collisioncheck(particles.get(i),particles.get(0));  //Particles 0 is the unique particle
if(collision)
{
tool.conservemomentum(particles.get(i), particles.get(0));
i = 51;
}
}
for(Particle p : particles)
{
p.updateposition(DeltaT);
}

repaint();
}

public void render(Graphics g, Particle p)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(new Color(252,18,235));
g2.fill(blob);
g2.draw(blob);
}

public void paintComponent(Graphics g)
{

g.clearRect(0, 0,700, 700);

for (Particle p : particles)
{
render(g,p);
}
}
}``````

## Ezzaral 2,714

``particlePanel.add(new Particle(5,3E-26,rand));``
``public void addParticle(Particle p )``