import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.Arrays;
import javax.swing.JApplet;
import javax.swing.JFrame;
import javax.swing.JPanel;
//Download by http://www.codesc.net
public class Billard4K extends JPanel implements Runnable, MouseListener, MouseMotionListener {
// GAME STATES
public final int WAITING_TO_START = 0;
public final int WAITING_TO_HIT = 1;
public final int MOVING = 2;
public final int FINISHING = 3;
public int state = 0;
// TABLE
double hR;
double[] tableX;
double[] tableY;
double[] holesX;
double[] holesY;
// BALLS
public int nballs;
public int nBallsOn;
double[] x;
double[] y;
double[] vx;
double[] vy;
double[] nextX;
double[] nextY;
double[] nextVx;
double[] nextVy;
boolean[] borderCollision;
boolean[][] collision;
boolean[] onTable;
double r = 10;
// RENDERING
Image backBuffer;
Image backGround;
// MOUSE
int mX;
int mY;
int mXPost;
int mYPost;
boolean clicked;
// STICK
public final int MAX_STRENGTH = 1000;
int sL = 300;
int actualStep = 0;
public Billard4K() {
super();
this.setBounds(50, 50, 700, 350);
//this.setResizable(false);
//this.setUndecorated(true);
//this.setVisible(true);
JFrame f = new JFrame("Billard4K");
f.add(this);
f.setBounds(0, 0, 700, 380);
f.setResizable(false);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.requestFocus();
init();
}
public void init() {
initTable();
initBalls();
backBuffer = this.createImage(this.getWidth(), this.getHeight());
//gBackBuffer = backBuffer.getGraphics();
//gBackBuffer.setFont(new Font("Courier", Font.BOLD, 20));
createBackGround();
this.addMouseListener(this);
this.addMouseMotionListener(this);
start();
}
public void initTable() {
hR = 16;
tableX = new double[] {
40,
this.getWidth()-40
};
tableY = new double[] {
tableX[0],
this.getHeight()-tableX[0]
};
holesX = new double[] {
tableX[0] + 20,
this.getWidth()/2,
tableX[1]-20
};
holesY = new double[] {
tableY[0] + 20,
this.tableY[1]-20
};
}
public void initBalls() {
nballs = 16;
x = new double[nballs];
y = new double[nballs];
vx = new double[nballs];
vy = new double[nballs];
nextX = new double[nballs];
nextY = new double[nballs];
nextVx = new double[nballs];
nextVy = new double[nballs];
borderCollision = new boolean[nballs];
collision = new boolean[nballs][nballs];
onTable = new boolean[nballs];
setBalls();
setWhiteBall();
}
public void setWhiteBall() {
x[0] = 1.0 *(holesX[2]-holesX[0]) / 3.0;
y[0] = this.getHeight() / 2;
vx[0] = 0;
vy[0] = 0;
boolean collisions = false;
boolean recolocate = false;
do {
collisions = false;
recolocate = false;
for (int i=1; !collisions && i<nballs; ++i) {
collisions = isBallsCollisionPre(0, i);
}
if (collisions) {
recolocate = true;
y[0] -= r;
if (y[0]<holesY[0]) y[0] = holesY[1]-r;
}
} while (recolocate);
onTable[0] = true;
}
public void setBalls() {
int ball=1;
nBallsOn = nballs - 1;
final double mul = Math.sqrt(3.5);
for (int col=0; col<5; ++col) {
double xN = this.getWidth()*2.0/3.0+col* mul *r;
double yN = this.getHeight()/2-col*r;
for (int row=0; row<=col; ++row) {
x[ball] = xN;
y[ball] = yN;
vx[ball] = 0;
vy[ball] = 0;
onTable[ball] = true;
yN += 2*r;
++ball;
}
}
}
public void createBackGround() {
backGround = this.createImage(this.getWidth(), this.getHeight());
Graphics g = backGround.getGraphics();
g.setColor(Color.GRAY);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(new Color(200, 100, 50).darker());
g.fill3DRect((int)(tableX[0]), (int)(tableY[0]), (int)(tableX[1]-tableX[0]), (int)(tableY[1]-tableY[0]), true);
g.setColor(Color.GREEN);
g.fill3DRect((int)(holesX[0]), (int)(holesY[0]), (int)(holesX[2]-holesX[0]), (int)(holesY[1]-holesY[0]), false);
g.setColor(Color.GREEN.brighter());
g.drawLine((int)(1.0 *(holesX[2]-holesX[0]) / 3.0), (int)holesY[0], (int)(1.0 *(holesX[2]-holesX[0]) / 3.0), (int)holesY[1]);
g.fillOval((int)(1.0 *(holesX[2]-holesX[0]) / 3.0)-2, (int)((holesY[1]+holesY[0])/2)-2, 4, 4);
g.drawArc((int)(1.0 *(holesX[2]-holesX[0]) / 3.0)-20, (int)((holesY[1]+holesY[0])/2)-20, 40, 40, 90, 180);
g.setColor(Color.BLACK);
double radio = hR-2;
for (int iX = 0; iX<3; ++iX) {
for (int iY = 0; iY<2; ++iY) {
g.fillOval((int)(holesX[iX]-radio), (int)(holesY[iY]-radio), (int)(2*radio), (int)(2*radio));
}
}
g.setColor(Color.YELLOW);
g.setFont(new Font("Courier", Font.PLAIN, 11));
g.drawString("http://es.geocities.com/luisja80", this.getWidth()-250, this.getHeight()-10);
}
public void start() {
(new Thread(this)).start();
}
public void run() {
long t1 = System.currentTimeMillis(), t2 = t1;
while (true) {
try {
t2 = System.currentTimeMillis();
switch (state) {
case WAITING_TO_HIT:
calculateNext(t2-t1);
collisions();
update();
break;
case MOVING:
calculateNext(t2-t1);
collisions();
update();
boolean allStopped = true;
for (int i=0; allStopped && i<nballs; ++i) {
allStopped = (vx[i]==0) && (vy[i]==0);
}
if (allStopped) {
state = WAITING_TO_HIT;
if (!onTable[0]) {
setWhiteBall();
}
}
if (nBallsOn==0) {