// The "PoolGame" class.
import java.awt.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
import java.applet.*;
public class PoolGame extends Frame
{
final int NUMOFBALLS = 16;
Ball[] ball = new Ball [NUMOFBALLS];
double t; //Amount of time until a collision occurs between the balls
final int DELAY = 50;
final int LEFTWALL = -18;
final int RIGHTWALL = 1000;
final int BOTTOMWALL = 500;
int checker = 0;
int check = 1;
int turn = 1;
final int TOPWALL = 1;
final double CLOSESTPOSSIBLE = 0.000000001; //Maximum distance the two balls can be apart and still be colliding (to stop it from getting stuck)
final int STARTX = 300;
final int STARTY = 230;
final int TOPBORDER = 13;
final int BOTTOMBORDER = -23;
final int RIGHTBORDER = -23;
final int LEFTBORDER = 12;
final double WALLFRICTION = 0.7;
final double FRICTION =0.03;
Image bg= Toolkit.getDefaultToolkit().getImage ("BG.JPG");
MediaTracker tracker=new MediaTracker (this);
public PoolGame ()
{
super ("PoolGame"); // Set the frame's name
setSize (RIGHTWALL, BOTTOMWALL); // Set the frame's size
show ();
for (int count = 0 ; count < NUMOFBALLS ; count++)
{
// //Initializes the balls
ball [count] = new Ball ();
ball [count].setX (((int) (Math.random () * (378 - 20 + 1))) + 1);
ball [count].setY (((int) (Math.random () * (378 - 20 + 1))) + 1);
// ball [count].setVX (((int) (Math.random () * (18))) - 5);
// ball [count].setVY (((int) (Math.random () * (18))) - 5);
// ball [count].setVY1 (ball [count].getVY ());
// ball [count].setVX1 (ball [count].getVX ());
ball [count].setVX1 (0);
ball [count].setVX (0);
ball [count].setVY (0);
ball [count].setVY1 (0);
ball [count].setRadius (20);
ball [count].setMass (Math.PI * (Math.pow (ball [count].getRadius (), 2)));
}
//
ball [1].setX (STARTX);
ball [1].setY (STARTY);
//
ball [2].setX (STARTX - 35);
ball [2].setY (STARTY - 20);
ball [3].setX (STARTX - 35);
ball [3].setY (STARTY + 20);
//
ball [4].setX (STARTX - 70);
ball [4].setY (STARTY);
ball [5].setX (STARTX - 70);
ball [5].setY (STARTY - 40);
ball [6].setX (STARTX - 70);
ball [6].setY (STARTY + 40);
//
ball [7].setX (STARTX - 105);
ball [7].setY (STARTY + 20);
ball [8].setX (STARTX - 105);
ball [8].setY (STARTY + 60);
ball [9].setX (STARTX - 105);
ball [9].setY (STARTY - 20);
ball [10].setX (STARTX - 105);
ball [10].setY (STARTY - 60);
//
ball [11].setX (STARTX - 140);
ball [11].setY (STARTY);
ball [12].setX (STARTX - 140);
ball [12].setY (STARTY + 40);
ball [13].setX (STARTX - 140);
ball [13].setY (STARTY - 40);
ball [14].setX (STARTX - 140);
ball [14].setY (STARTY + 80);
ball [15].setX (STARTX - 140);
ball [15].setY (STARTY - 80);
ball [0].setX (STARTX + 200);
ball [0].setY (STARTY);
}
//lets us know if 2 balls are moving towards each other (to add efficiency and not be forced to check for collision each time)
public boolean movingTowards (Ball b1, Ball b2)
{
//Formula found on the net that tells me if they are moving towards each other.
return (b2.getX () - b1.getX ()) * (b1.getVX () - b2.getVX ()) + (b2.getY () - b1.getY ()) * (b1.getVY () - b2.getVY ()) > 0;
}
public double timeToCollide () //tells me the lowest number of frames until a collision occurs.
{
double t = Integer.MAX_VALUE;
double a, b, c, d, discriminent; //this is done to break up a very large formula for t.
//loops through every pair of balls
for (int i = 0 ; i < ball.length ; i++)
{
for (int o = 1 + i ; o < ball.length ; o++)
{
if (movingTowards (ball [i], ball [o]))
{
//A formula found on the net that calculates when two balls will collide
a = Math.pow (ball [i].getVX (), 2) + Math.pow (ball [i].getVY (), 2) - 2 * ball [i].getVX () * ball [o].getVX () + Math.pow (ball [o].getVX (), 2) - 2 * ball [i].getVY () * ball [o].getVY () + Math.pow (ball [o].getVY (), 2);
b = -ball [i].getX () * ball [i].getVX () - ball [i].getY () * ball [i].getVY () + ball [i].getVX () * ball [o].getX () + ball [i].getVY () * ball [o].getY () + ball [i].getX () * ball [o].getVX () -
ball [o].getX () * ball [o].getVX () + ball [i].getY () * ball [o].getVY () - ball [o].getY () * ball [o].getVY ();
c = Math.pow (ball [i].getVX (), 2) + Math.pow (ball [i].getVY (), 2) - 2 * ball [i].getVX () * ball [o].getVX () + Math.pow (ball [o].getVX (), 2) - 2 * ball [i].getVY () * ball [o].getVY () + Math.pow (ball [o].getVY (), 2);
d = Math.pow (ball [i].getX (), 2) + Math.pow (ball [i].getY (), 2) - Math.pow (ball [i].getRadius (), 2) - 2 * ball [i].getX () * ball [o].getX () + Math.pow (ball [o].getX (), 2) - 2 * ball [i].getY () * ball [o].getY () +
Math.pow (ball [o].getY (), 2) - 2 * ball [i].getRadius () * ball [o].getRadius () - Math.pow (ball [o].getRadius (), 2);
discriminent = Math.pow ((-2 * b), 2) - 4 * c * d;
//If our final discriminent is > 0 it means a collision will occur and we will compare the current t to our new t.
//We update it to the lowest possible t to get the smallest amount of time.
if (discriminent >= 0)
t = Math.min (Math.min (t, 0.5 * (2 * b - Math.sqrt (discriminent)) / a), 0.5 * (2 * b + Math.sqrt (discriminent)) / a);
}
}
}
return t;
}
public boolean mouseDown (Event event, int x, int y)
{
ball [0].setVX ((ball [0].getX () + 20 - x) / 5);
ball [0].setVX1 ((ball [0].getX () + 20 - x) / 5);
ball [0].setVY1 ((ball [0].getY () + 20 - y) / 5);
ball [0].setVY ((ball [0].getY () + 20 - y) / 5);
if (turn == 1)
turn = 2;
else
turn = 1;
checker = 0;
repaint ();
return true;
}
public double update () // updates t and sets the new X and Y of the balls
{
//should t be bigger then 1, we want the maximum frame incrememnts to be 1.
double t = Math.min (1, timeToCollide ());
for (int count = 0 ; count < ball.length ; count++)
{
ball [count].setX (ball [count].getX () + ball [count].getVX () * t);
ball [count].setY (ball [count].getY () + ball [count].getVY () * t);
}
return t;
}
public void collide (Ball b1, Ball b2)
{
//adjusts velocity according to mass of the ball, and radius. Formula was found on the net.
double nx = (b1.getX () - b2.getX ()) / (b1.getRadius () + b2.getRadius ());
double ny = (b1.getY () - b2.getY ()) / (b1.getRadius () + b2.getRadius ());
double a1 = b1.getVX () * nx + b1.getVY () * ny;
double a2 = b2.getVX () * nx + b2.getVY () * ny;
double p = 2 * (a1 - a2) / (b1.getMass () + b2.getMass ());
b1.setVX1 (b1.getVX () - p * nx * b2.getMass ());
b1.setVY1 (b1.getVY () - p * ny * b2.getMass ());
b2.setVX1 (b2.getVX () + p * nx * b1.getMass ());
b2.setVY1 (b2.getVY () + p * ny * b1.getMass ());
}
//the method that checks for collision between balls and collision off the wall.
public void checkForCollision ()
{
//loops through every pair of balls
for (int i = 0 ; i < ball.length ; i++)
{
for (int o = 1 + i ; o < ball.length ; o++)
{
if (movingTowards (ball [i], ball [o]) && Math.pow ((ball [o].getX () - ball [i].getX ()), 2) + Math.pow ((ball [o].getY () - ball [i].getY ()), 2) <= (Math.pow ((ball [i].getRadius () + ball [o].getRadius () + CLOSESTPOSSIBLE), 2)))
{
//calls the following if a collision has occured.
collide (ball [i], ball [o]);
}
}
//deals with the collision of the walls.
if ((ball [i].getX () - ball [i].getRadius () + CLOSESTPOSSIBLE) < LEFTWALL + LEFTBORDER)
{
ball [i].setVX1 (ball [i].getVX1 () * -1);
ball [i].setX (LEFTWALL - CLOSESTPOSSIBLE + ball [i].getRadius () + LEFTBORDER);
ball [i].setVX (ball [i].getVX () * WALLFRICTION);
ball [i].setVX1 (ball [i].getVX1 () * WALLFRICTION);
ball [i].setVY (ball [i].getVY () * WALLFRICTION);
ball [i].setVY1 (ball [i].getVY1 () * WALLFRICTION);
}
else if ((ball [i].getX () + ball [i].getRadius () + CLOSESTPOSSIBLE) > RIGHTWALL + RIGHTBORDER)
{
ball [i].setVX1 (ball [i].getVX1 () * -1);
ball [i].setX (RIGHTWALL - CLOSESTPOSSIBLE - ball [i].getRadius () + RIGHTBORDER);
ball [i].setVX (ball [i].getVX () * WALLFRICTION);
ball [i].setVX1 (ball [i].getVX1 () * WALLFRICTION);
ball [i].setVY (ball [i].getVY () * WALLFRICTION);
ball [i].setVY1 (ball [i].getVY1 () * WALLFRICTION);
}
if ((ball [i].getY () - ball [i].getRadius () - CLOSESTPOSSIBLE) < TOPWALL + TOPBORDER)
{
ball [i].setVY1 (ball [i].getVY1 () * -1);
ball [i].setY (TOPWALL + CLOSESTPOSSIBLE + ball [i].getRadius () + TOPBORDER);
ball [i].setVX (ball [i].getVX () * WALLFRICTION);
ball [i].setVX1 (ball [i].getVX1 () * WALLFRICTION);
ball [i].setVY (ball [i].getVY () * WALLFRICTION);
ball [i].setVY1 (ball [i].getVY1 () * WALLFRICTION);
}
else if ((ball [i].getY () + ball [i].getRadius () + CLOSESTPOSSIBLE) > BOTTOMWALL + BOTTOMBORDER)
{
ball [i].setVY1 (ball [i].getVY1 () * -1);
ball [i].setY (BOTTOMWALL + CLOSESTPOSSIBLE - ball [i].getRadius () + BOTTOMBORDER);
ball [i].setVX (ball [i].getVX () * WALLFRICTION);
ball [i].setVX1 (ball [i].getVX1 () * WALLFRICTION);
ball [i].setVY (ball [i].getVY () * WALLFRICTION);
ball [i].setVY1 (ball [i].getVY1 () * WALLFRICTION);
}
}
//VX1 and VY1 are temporary velocity storage because I run into problems otherwise so I re-set the current velocity to the value of VX1 and VY1
for (int count = 0 ; count < ball.length ; count++)
{
ball [count].setVX (ball [count].getVX1 ());
ball [count].setVY (ball [count].getVY1 ());
}
}
public void paint (Graphics g)
{
//loops through until all balls have come to a halt
while (checker < ball.length)
{
checker = 0;
g.setColor (Color.white);
g.fillRect (0, 0, RIGHTWALL, BOTTOMWALL);
for (int count = 0 ; count < ball.length ; count++)
{
if (count == 0)
g.setColor (Color.red);
else
g.setColor (Color.blue);
g.fillOval ((int) Math.round (ball [count].getX ()), (int) Math.round (ball [count].getY ()), 41, 41); //draws the balls
}
checkForCollision ();
t = update ();
Delay.stop ((int) Math.round (DELAY * t));
for (int count = 0 ; count < ball.length ; count++)
{
if (ball [count].getVX () > 0)
{
ball [count].setVX (ball [count].getVX () - FRICTION);
ball [count].setVX1 (ball [count].getVX1 () - FRICTION);
}
else if (ball [count].getVX () < 0)
{
ball [count].setVX (ball [count].getVX () + FRICTION);
ball [count].setVX1 (ball [count].getVX1 () + FRICTION);
}
if (ball [count].getVY () > 0)
{
ball [count].setVY (ball [count].getVY () - FRICTION);
ball [count].setVY1 (ball [count].getVY1 () - FRICTION);
}
else if (ball [count].getVY () < 0)
{
ball [count].setVY (ball [count].getVY () + FRICTION);
ball [count].setVY1 (ball [count].getVY1 () + FRICTION);
}
if (ball [count].getVX () <= FRICTION && ball [count].getVY () <= FRICTION && ball [count].getVX () >= -FRICTION && ball [count].getVY () >= -FRICTION)
{
checker += 1;
}
}
}
for (int count = 0 ; count < ball.length ; count++)
{
if (count == 0)
g.setColor (Color.red);
else
g.setColor (Color.blue);
g.fillOval ((int) Math.round (ball [count].getX ()), (int) Math.round (ball [count].getY ()), 41, 41); //draws the balls
g.setColor (Color.green);
}
}
public static void main (String[] args)
{
new PoolGame (); // Create a PoolGame frame
} // main method
}
//ball class and contains the attributes of the individual balls.
class Ball
{
private double x;
private double y;
private double vx;
private double vy;
private double vx1;
private double vy1;
private double radius;
private double mass;
public Ball () //double x, double y, double vx, double vy, double radius, double mass)
{
// this.x = x;
// this.y = y;
// this.vx = vx;
// this.vy = vy;
// this.radius = radius;
// this.mass = mass;
}
public void setX (double x)
{
this.x = x;
}
public void setY (double y)
{
this.y = y;
}
public void setVX (double vx)
{
this.vx = vx;
}
public void setVY (double vy)
{
this.vy = vy;
}
public void setVY1 (double vy1)
{
this.vy1 = vy1;
}
public void setRadius (double radius)
{
this.radius = radius;
}
public void setMass (double mass)
{
this.mass = mass;
}
public void setVX1 (double vx1)
{
this.vx1 = vx1;
}
public double getX ()
{
return x;
}
public double getY ()
{
return y;
}
public double getVX ()
{
return vx;
}
public double getVY ()
{
return vy;
}
public double getVY1 ()
{
return vy1;
}
public double getVX1 ()
{
return vx1;
}
public double getRadius ()
{
return radius;
}
public double getMass ()
{
return mass;
}
} // PoolGame class
|