BounceArea.java


BounceArea.java

import javafx.scene.Scene;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.util.Duration;
import java.util.*;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;

import javafx.collections.*;


public class BounceArea extends Pane
{
    Timer myTimer;
    double wd, ht;
    ArrayList<Ball> balls = new ArrayList<Ball>();
    ArrayList<Ball> fixedPts = new ArrayList<Ball>();
    ArrayList<WallSeg> segs = new ArrayList<WallSeg>();
    ArrayList<Collision> collisions = new ArrayList<Collision>();
    boolean done = false;
    Timeline animation;
    double simtime = 0.0;

    
    BounceArea()
    {
	Ball b;
	wd = 740;
	ht = 500;

	setStyle("-fx-background-color: honeydew;");

	make_area();

	Color [] colors = {Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA, Color.YELLOW};
	String [] names = {"red","green","blue","magneta","yellow"};
	for (int k=0; k<5; k++) {
		b = new Ball();
		b.randomize(20.0,wd,ht);
		while (intersect_world(b)) b.randomize(10.0,wd,ht);
		b.setColor(colors[k]);
		b.set_name(names[k]);
		balls.add(b);
		getChildren().add(b.circle);
	}

    	// Create a handler for animation
    	EventHandler<ActionEvent> eventHandler = e -> {
		update2();
     };

    // Create an animation
        animation = new Timeline(
        new KeyFrame(Duration.millis(50), eventHandler));
        animation.setCycleCount(Timeline.INDEFINITE);
        animation.play(); // Start animation


    }

    void make_area()
    {
	double sw = 2.0; // stroke width
	ObservableList<Node> ol = getChildren();
	// draw grid
	int n;
	double w = 80;
	Path path1 = new Path();	
	ObservableList<PathElement> ob = path1.getElements();
	for (n=0; n<7; n++) {
	    ob.add(new MoveTo(10,10+n*w));
	    ob.add(new LineTo(10+9*w,10+n*w));
	}
	for (n=0; n<10; n++) {
	    ob.add(new MoveTo(10+n*w,10));
	    ob.add(new LineTo(10+n*w,10+6*w));
        }
	path1.setStroke(Color.rgb(200,200,255));

	// room boundaries
	Ball pt1, pt2, pt3, pt4, pt5;
	pt1 = new Ball(10, 10);
	pt2 = new Ball(730, 10);
	pt3 = new Ball(730, 490);
	pt4 = new Ball(10, 490);
	segs.add(new WallSeg(pt1,pt2));
	segs.add(new WallSeg(pt2,pt3));
	segs.add(new WallSeg(pt3,pt4));
	segs.add(new WallSeg(pt4,pt1));

	// draw room boundaries
	Path path2 = new Path();
	ob = path2.getElements();
	ob.add(new MoveTo(pt1.px,pt1.py));
	ob.add(new LineTo(pt2.px,pt2.py));
	ob.add(new LineTo(pt3.px,pt3.py));
	ob.add(new LineTo(pt4.px,pt4.py));
	ob.add(new ClosePath());
	path2.setStroke(Color.BLACK);
	path2.setStrokeWidth(sw);

	// obstruction1
	Path path3 = new Path();
	ob = path3.getElements();
	pt1 = new Ball(540, 300);
	fixedPts.add(pt1);
	pt2 = new Ball(540, 160);
	fixedPts.add(pt2);
	pt3 = new Ball(300, 160);
	fixedPts.add(pt3);
	pt4 = new Ball(300, 390);
	fixedPts.add(pt4);
	pt5 = new Ball(540, 390);
	fixedPts.add(pt5);
	ob.add(new MoveTo(pt1.px,pt1.py));
	ob.add(new LineTo(pt2.px,pt2.py));
	ob.add(new LineTo(pt3.px,pt3.py));
	ob.add(new LineTo(pt4.px,pt4.py));
	ob.add(new LineTo(pt5.px,pt5.py));
	path3.setStroke(Color.BLACK);
	path3.setStrokeWidth(sw);

	segs.add(new WallSeg(pt1,pt2));
	segs.add(new WallSeg(pt2,pt3));
	segs.add(new WallSeg(pt3,pt4));
	segs.add(new WallSeg(pt4,pt5));

	// obstruction 2
	Path path4 = new Path();
	ob = path4.getElements();
	pt1 = new Ball(200, 490);
	pt2 = new Ball(200, 200);
	pt3 = new Ball(100, 200);
	segs.add(new WallSeg(pt1,pt2));
	segs.add(new WallSeg(pt2,pt3));
	fixedPts.add(pt2);
	fixedPts.add(pt3);
	ob.add(new MoveTo(pt1.px,pt1.py));
	ob.add(new LineTo(pt2.px,pt2.py));
	ob.add(new LineTo(pt3.px,pt3.py));
	path4.setStroke(Color.BLACK);
	path4.setStrokeWidth(sw);

	ol.addAll(path1,path2,path3,path4);
    }

   public boolean intersect_world(Ball bt)
   {
        for (Ball b: balls) {
	   if (b.dist(bt)<50) return true;
	}
	for (WallSeg seg: segs) {
		if (seg.dist(bt)<0) return true;
	}
	return false;
   }



    public boolean check_distance()
    {
	double dist;
	boolean flag = false;
	int nballs = balls.size();
	for (int i=0; i<nballs-1; i++) {
	    for (int j=i+1; j<nballs; j++) {
		Ball b1 = balls.get(i);
		Ball b2 = balls.get(j);
		dist = b1.dist(b2);
		if (dist<-0.01) {
			System.out.println("dist " + dist + " " + b1 + b2);
			double dx = b2.px-b1.px;
			double dy = b2.py-b1.py;
			System.out.println( b1.info());
			System.out.println( b2.info());
			System.out.println("dx " + dx + " dy " + dy);
			System.out.println("sep " + Math.hypot(dx,dy) + " radius " + (b1.radius+b2.radius));
			flag = true;
		}
	    }

	}
	return flag;
    }


    double wd1, ht1;

    public void update2()
    {
	wd1 = getWidth();
	ht1 = getHeight();
	double tstep, tmore;
	tstep = 1.0;
	tmore = tstep;
	simtime += tstep;
	while (tmore>0.0) {
	    update_collision_list(tmore);
	    if (collisions.size()>0) {
		
		java.util.List<Collision> list = collisions;	 
		Collections.<Collision>sort(list);
		Collision c = collisions.get(0);
		tstep = c.timestep;
		tmore = tmore - tstep;
		for (Ball ball: balls) ball.move(tstep);
		c.update_velocity();
	    }
	    else {
		tstep = tmore;
		tmore = 0.0;
		for (Ball ball: balls) ball.move(tstep);
	    }
	}
    }

    public void update_collision_list(double tstep)
    {
	Collision c;
	collisions.clear();
	double t;
	for (Ball ball: balls)	{
	    t = ball.intersect_window_vertical(wd1);
	    if (t>0.0 && t<tstep) collisions.add(new Collision(t,ball,1));
	    t = ball.intersect_window_horizontal(ht1);
	    if (t>0.0 && t<tstep) collisions.add(new Collision(t,ball,2));

	    for (WallSeg seg: segs) {
		t = seg.intersect(ball);
		if (t<-1.5) System.out.println(seg.str);
		if (t>0.0 && t<tstep) collisions.add(new Collision(t,ball,seg));
	    }

	    for (Ball pt: fixedPts) {
		t = ball.intersect(pt);
		if (t>0.0 && t<tstep) {
			c = new Collision(t,ball,pt);
			collisions.add(c);
			c.ndx = -2;
		}
	    }
	}
	int nballs = balls.size();
	for (int i=0; i<nballs-1; i++) {
	    for (int j=i+1; j<nballs; j++) {
		Ball b1 = balls.get(i);
		Ball b2 = balls.get(j);
		t = b1.intersect(b2);
		if (t>0.0 && t<tstep) collisions.add(new Collision(t,b1,b2));
	    }
	}
    }	
}


Maintained by John Loomis, updated Sat Mar 03 12:46:03 2018