import javax.swing.JApplet; import javax.swing.JButton; import java.awt.Graphics; import java.awt.Color; import java.util.Scanner; import java.awt.Container; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.Canvas; import javax.swing.JTextField; import java.awt.event.*; import javax.swing.Timer; import java.awt.Font; public class TwoBouncingBallNoCollision extends JApplet implements ActionListener { private Block ceiling; private int ceilingMax = 35; private int ceilingMin = 25; private Block floor; private int floorMin = 290; private int floorMax = 300; private Block leftWall; private Block rightWall; private int leftBound = 0; private int rightBound = 300; private int numberOfBalls = 2; private Ball[] ball; private JTextField[] textSetX; private JTextField[] textSetY; private JTextField[] textSetVx; private JTextField[] textSetVy; private JTextField[] textSetM; private double time; private double dt = 0.005;//initial time step. private boolean runTime; private int animationTimeInterval = 1; private double timeToWallCollision; private double timeToBallCollision; private Timer timer; public void init() { timer = new Timer(animationTimeInterval, new TimerAction()); /*Scanner keyboard = new Scanner(System.in); System.out.println("How many balls?"); numberOfBalls = keyboard.nextInt();*/ Container contentPane = this.getContentPane(); contentPane.setSize(1000, 1000); contentPane.setBackground(Color.WHITE); contentPane.setLayout(null); ball = new Ball[numberOfBalls]; for (int i = 0; i < numberOfBalls; i++) { ball[i] = new Ball(); ball[i].setCoordinates(150 + 20*i, 150 + 20*i, 10); ball[i].setVelocity(30, 30); ball[i].setMass(5); } JButton xValues = new JButton("X"); xValues.setBackground(Color.WHITE); xValues.setBounds(300, 20, 50, 30); contentPane.add(xValues); setVisible(true); JButton yValues = new JButton("Y"); yValues.setBackground(Color.WHITE); yValues.setBounds(350, 20, 50, 30); contentPane.add(yValues); setVisible(true); JButton vxValues = new JButton("Vx"); vxValues.setBackground(Color.WHITE); vxValues.setBounds(400, 20, 50, 30); contentPane.add(vxValues); setVisible(true); JButton vyValues = new JButton("Vy"); vyValues.setBackground(Color.WHITE); vyValues.setBounds(450, 20, 50, 30); contentPane.add(vyValues); setVisible(true); JButton mValues = new JButton("Mass"); mValues.setBackground(Color.WHITE); mValues.setBounds(495, 20, 60, 30); contentPane.add(mValues); setVisible(true); textSetX = new JTextField[numberOfBalls]; for (int i = 0; i < numberOfBalls; i++) { textSetX[i] = new JTextField(3); textSetX[i].setText(Double.toString(ball[i].getXCoordinate())); Font curFont = textSetX[i].getFont(); textSetX[i].setFont(new Font(curFont.getFontName(), curFont.getStyle(), 9)); textSetX[i].setBounds(300, 50 + 15*i, 50, 25); contentPane.add(textSetX[i]); textSetX[i].setVisible(true); } textSetY = new JTextField[numberOfBalls]; for (int i = 0; i < numberOfBalls; i++) { textSetY[i] = new JTextField(3); textSetY[i].setText(Double.toString(ball[i].getYCoordinate())); Font curFont = textSetY[i].getFont(); textSetY[i].setFont(new Font(curFont.getFontName(), curFont.getStyle(), 9)); textSetY[i].setBounds(350, 50 + 15*i, 50, 25); contentPane.add(textSetY[i]); textSetY[i].setVisible(true); } textSetVx = new JTextField[numberOfBalls]; for (int i = 0; i < numberOfBalls; i++) { textSetVx[i] = new JTextField(3); textSetVx[i].setText(Double.toString(ball[i].getXVelocity())); Font curFont = textSetVx[i].getFont(); textSetVx[i].setFont(new Font(curFont.getFontName(), curFont.getStyle(), 9)); textSetVx[i].setBounds(400, 50 + 15*i, 50, 25); contentPane.add(textSetVx[i]); textSetVx[i].setVisible(true); } textSetVy = new JTextField[numberOfBalls]; for (int i = 0; i < numberOfBalls; i++) { textSetVy[i] = new JTextField(3); textSetVy[i].setText(Double.toString(ball[i].getYVelocity())); Font curFont = textSetVy[i].getFont(); textSetVy[i].setFont(new Font(curFont.getFontName(), curFont.getStyle(), 9)); textSetVy[i].setBounds(450, 50 + 15*i, 50, 25); contentPane.add(textSetVy[i]); textSetVy[i].setVisible(true); } textSetM = new JTextField[numberOfBalls]; for (int i = 0; i < numberOfBalls; i++) { textSetM[i] = new JTextField(3); textSetM[i].setText(Double.toString(ball[i].getMass())); Font curFont = textSetM[i].getFont(); textSetM[i].setFont(new Font(curFont.getFontName(), curFont.getStyle(), 9)); textSetM[i].setBounds(500, 50 + 15*i, 50, 25); contentPane.add(textSetM[i]); textSetM[i].setVisible(true); } JButton startButton = new JButton("Start"); startButton.setBackground(Color.GREEN); startButton.setBounds(300, 100, 50, 50); startButton.addActionListener(this); contentPane.add(startButton); setVisible(true); //buttonPanel.add(startButton); //contentPane.add(buttonPanel, BorderLayout.EAST); JButton stopButton = new JButton("Stop"); stopButton.setBackground(Color.RED); stopButton.setBounds(350, 100, 50, 50); stopButton.addActionListener(this); contentPane.add(stopButton); setVisible(true); int[] xCeiling = {leftBound, leftBound, rightBound, rightBound}; int[] yCeiling = {ceilingMin, ceilingMax, ceilingMax, ceilingMin}; ceiling = new Block("Ceiling", Color.BLACK, xCeiling, yCeiling, xCeiling.length); //roomPanel.add(ceiling); int[] xFloor = {leftBound, leftBound, rightBound, rightBound}; int[] yFloor = {floorMin, floorMax, floorMax, floorMin}; floor = new Block("Floor", Color.BLACK, xFloor, yFloor, xFloor.length); //roomPanel.add(floor); int[] xLeftWall = {leftBound, leftBound, leftBound + 10, leftBound + 10}; int[] yLeftWall = {ceilingMin, floorMax, floorMax, ceilingMin}; leftWall = new Block("LeftWall", Color.BLACK, xLeftWall, yLeftWall, xLeftWall.length); int[] xRightWall = {rightBound - 10, rightBound -10, rightBound, rightBound}; int[] yRightWall = {ceilingMin, floorMax, floorMax, ceilingMin}; rightWall = new Block("RightWall", Color.BLACK, xRightWall, yRightWall, xRightWall.length); JButton setPositionsButton = new JButton("Set"); setPositionsButton.setBackground(Color.WHITE); setPositionsButton.setBounds(300, 150, 40, 40); setPositionsButton.addActionListener(this); contentPane.add(setPositionsButton); setVisible(true); JButton resetPositionsButton = new JButton("Reset"); resetPositionsButton.setBackground(Color.WHITE); resetPositionsButton.setBounds(350, 150, 60, 40); resetPositionsButton.addActionListener(this); contentPane.add(resetPositionsButton); setVisible(true); JButton reverse = new JButton("Reverse"); reverse.setBackground(Color.WHITE); reverse.setBounds(400, 100, 75, 50); reverse.addActionListener(this); contentPane.add(reverse); setVisible(true); //contentPane.add(roomPanel, BorderLayout.EAST); } public void paint(Graphics canvas) { canvas.setClip(0, 0, 305, 305); canvas.clearRect(0, 0, 305, 305); ceiling.draw(canvas); floor.draw(canvas); leftWall.draw(canvas); rightWall.draw(canvas); for (int i = 0; i < numberOfBalls; i++) { ball[i].draw(canvas); } } public void actionPerformed(ActionEvent a) { if (a.getActionCommand() == "Start") { //System.out.print("GO!"); setAnimation(true); } else if (a.getActionCommand() == "Stop") { setAnimation(false); for (int i = 0; i < numberOfBalls; i++) { //System.out.println("Position Ball " + i + ": " + ball[i].getXCoordinate() + ", " + ball[i].getYCoordinate() + ", " //+ ball[i].getXVelocity() + ", " + ball[i].getYVelocity()); } //+ "Time: " + time + "\t" + "Time to next wall collision: " + timeToWallCollision); } else if (a.getActionCommand() == "Set") { for (int i = 0; i < numberOfBalls; i++) { ball[i].setCoordinates(Double.parseDouble(textSetX[i].getText().trim()), Double.parseDouble(textSetY[i].getText().trim())); ball[i].setVelocity(Double.parseDouble(textSetVx[i].getText().trim()), Double.parseDouble(textSetVy[i].getText().trim())); } repaint(); } else if (a.getActionCommand() == "Reset") { for (int i = 0; i < numberOfBalls; i++) { ball[i].setCoordinates(150 + 20*i, 150 + 20*i, 10); ball[i].setVelocity(30, 30); ball[i].setMass(5); } repaint(); } else if (a.getActionCommand() == "Reverse") { for (int i = 0; i < numberOfBalls; i++) { ball[i].setVelocity(-ball[i].getXVelocity(), -ball[i].getYVelocity()); } } else { //System.out.println("Error"); System.exit(0); } } public void setAnimation(boolean turnOn) { //annimationTimeInterval = 200; // Milliseconds between updates. if (turnOn) { timer.start(); // start animation by starting the timer. runTime = true; } else { runTime = false; // timer.stop()-->why doesn't it work? } } public double distanceToCollision(double x, double y, double x2, double y2) { MyMathOperations distanceCalculation = new MyMathOperations(); return distanceCalculation.distanceCalculation(x, y, x2, y2); } class TimerAction implements ActionListener { public void actionPerformed(ActionEvent e) { time = 0.0; if (runTime) { timeToWallCollision = 1.0/0.0; timeToBallCollision = 1.0/0.0; int trackLastJ = 1; int trackLastI = 0; dt = 0.005; /*predict timeToBallCollision**/ for (int i = 0; i < (numberOfBalls - 1); i++) { for (int j = i +1; j < (numberOfBalls); j++) { double t = ball[i].timeToCollision(ball[j]); //System.out.println("t calculated for " + i + " to " + j + "=" + t); if (t <= ball[trackLastI].timeToCollision(ball[trackLastJ])) { ball[i].setCollidingBallObject(ball[j]); timeToBallCollision = t;//This way timeToBallCollision is set to the soonest collision to occur //System.out.println("Ball " + i + " time to collision with " + j + " = " + timeToBallCollision); if (timeToBallCollision <= dt && timeToBallCollision < ball[trackLastI].timeToCollision(ball[trackLastJ])) { ball[trackLastI].setWillCollideWithBallThisTimeStep(false); //System.out.println("Set " + trackLastI + " false"); } if (timeToBallCollision <= dt) { ball[i].setWillCollideWithBallThisTimeStep(true); //System.out.println("Set " + i + " true"); } trackLastJ = j; trackLastI = i; } } } /*predict timeToWallCollision**/ for (int i = 0; i < numberOfBalls; i++) { if (ball[i].getYVelocity() > 0) { double t = distanceToCollision(ball[i].getXCoordinate(), ball[i].getYCoordinate(), ball[i].getXCoordinate(), floorMin - ball[i].getRadius()) / Math.abs(ball[i].getYVelocity()); if (t <= timeToWallCollision) { timeToWallCollision = t;//This way timeToWallCollision is set to the soonest collision to occur if (timeToWallCollision <= dt) ball[i].setWillCollideWithWallThisTimeStep(true); ball[i].setCollidingStationaryObject(floor); } } else if (ball[i].getYVelocity() < 0) { double t = distanceToCollision(ball[i].getXCoordinate(), ball[i].getYCoordinate(), ball[i].getXCoordinate(), ceilingMax + ball[i].getRadius()) / Math.abs(ball[i].getYVelocity()); if (t <= timeToWallCollision) { timeToWallCollision = t; if (timeToWallCollision <= dt) ball[i].setWillCollideWithWallThisTimeStep(true); ball[i].setCollidingStationaryObject(ceiling); } } if (ball[i].getXVelocity() > 0) { double t = distanceToCollision(ball[i].getXCoordinate(), ball[i].getYCoordinate(), rightBound - 10 - ball[i].getRadius(), ball[i].getYCoordinate()) / Math.abs(ball[i].getXVelocity()); if (t <= timeToWallCollision) { timeToWallCollision = t; if (timeToWallCollision <= dt) ball[i].setWillCollideWithWallThisTimeStep(true); ball[i].setCollidingStationaryObject(rightWall); } } if (ball[i].getXVelocity() < 0) { double t = distanceToCollision(ball[i].getXCoordinate(), ball[i].getYCoordinate(), leftBound + 10 + ball[i].getRadius(), ball[i].getYCoordinate()) / Math.abs(ball[i].getXVelocity()); if (t <= timeToWallCollision) { timeToWallCollision = t; if (timeToWallCollision <= dt) ball[i].setWillCollideWithWallThisTimeStep(true); ball[i].setCollidingStationaryObject(leftWall); } } } /*update position of ball[i] depending on condition**/ for (int i = 0; i < numberOfBalls; i++) { dt = 0.005; /*If the ball leaves the screen, have it enter on the opposite side**/ /*if ((ball[i].getXCoordinate()) <= (leftBound - ball[i].getRadius()) && ball[i].getXVelocity() < 0) ball[i].setCoordinates(rightBound + ball[i].getXCoordinate(), ball[i].getYCoordinate()); else if ((ball[i].getXCoordinate()) >= (rightBound - ball[i].getRadius()) && ball[i].getXVelocity() > 0) ball[i].setCoordinates(leftBound - ball[i].getRadius(), ball[i].getYCoordinate());*/ /*If the timeToBallCollision < dt and less than timeToWallCollision , move the ball to the collision and recalculate**/ /*if (timeToBallCollision <= dt && timeToBallCollision < timeToWallCollision && timeToBallCollision > 0) { dt = timeToBallCollision; ball[i].updatePosition(timeToBallCollision); /*if (ball[i].getCollisionBallAnswer()) { ball[i].bounce(ball[i].getCollidingBallObject()); }*/ //System.out.println("Collision! \n" + timeToBallCollision); /*If the timeToWallCollision is less than dt and is less that timeToBallCollision, move the ball to the wall and recalculate**/ if (timeToWallCollision <= (dt) && timeToWallCollision > 0 && timeToWallCollision < timeToBallCollision) { dt = timeToWallCollision; ball[i].updatePosition(timeToWallCollision); /*if (ball[i].getCollisionWallAnswer()) ball[i].bounce(ball[i].getCollidingStationaryObject()); System.out.println("wall bounce");*/ } /*Advance ball normal dt. If collision occured, bounce,**/ else { /*bounce off floor**/ /*if (ball[i].getYCoordinate() >= (floorMin - ball[i].getRadius())) { //ball[i].bounce(ball[i].getCollidingStationaryObject()); ball[i].setVelocity((ball[i].getXVelocity()), -1*(ball[i].getYVelocity())); System.out.println("floor bounce"); }*/ /*bounce off ceiling**/ /*else if (ball[i].getYCoordinate() <= (ceilingMax + ball[i].getRadius())) { ball[i].setVelocity((ball[i].getXVelocity()), -1*(ball[i].getYVelocity())); System.out.println("ceiling bounce"); }*/ /*bounce off another ball**/ /*for (int j = i +1; j < numberOfBalls; j++) { if ((distanceToCollision(ball[i].getXCoordinate(), ball[i].getYCoordinate(), ball[j].getXCoordinate(), ball[j].getYCoordinate())) <= (ball[i].getRadius() + ball[j].getRadius())) ball[i].bounce(ball[j]); }**/ ball[i].updatePosition(dt); } } for (int i = 0; i < numberOfBalls; i++) { if (ball[i].getCollisionBallAnswer()) { //System.out.println("Bounce!"); //ball[i].bounce(ball[i].getCollidingBallObject()); ball[i].setWillCollideWithBallThisTimeStep(false); (ball[i].getCollidingBallObject()).setWillCollideWithBallThisTimeStep(false); } } for (int i = 0; i < numberOfBalls; i++) { if (ball[i].getCollisionWallAnswer()) { if(ball[i].getCollidingStationaryObject() == floor || ball[i].getCollidingStationaryObject() == ceiling) ball[i].setVelocity((ball[i].getXVelocity()), -1*(ball[i].getYVelocity())); if(ball[i].getCollidingStationaryObject() == rightWall || ball[i].getCollidingStationaryObject() == leftWall) ball[i].setVelocity((-1* ball[i].getXVelocity()), (ball[i].getYVelocity())); ball[i].setWillCollideWithWallThisTimeStep(false); } } time = time + dt; repaint(); } } } }