Implementation of Galton board in java - java

I am writing the implementation of Galton Board in Java by using Java awt, Swing and thread. My Program has three text field to choose number of slots, number of balls, and number of ball drops at the same time, two buttons one for display and one for start the program. I try to make it work like I can choose the amount of balls and click start and the balls auto falling down the chimney. Currently, My program be able to drop one ball and running fine, but I don't know how to implement that be able drop more than one ball. Any suggestions or help are appreciated, Thank you. This is Main.Class
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;
public class Main extends JFrame {
private String num_slots;
private String num_balls;
private String ball_free;
private JButton Display;
private JButton Start;
private JPanel textpanel;
private JPanel mainpanel;
private JPanel graphpanel;
public Main() {
textpanel = new JPanel();
textpanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 20));
textpanel.add(new JLabel("Number of Slots"));
final JTextField text1 = new JTextField(10);
textpanel.add(text1);
textpanel.add(new JLabel("Number of Balls"));
final JTextField text2 = new JTextField(10);
textpanel.add(text2);
textpanel.add(new JLabel("How many balls can be freed"));
final JTextField text3 = new JTextField(10);
textpanel.add(text3);
Display = new JButton("Display");
textpanel.add(Display);
Start = new JButton("Start");
textpanel.add(Start);
// Create panel p2 to hold a text field and p1
mainpanel = new JPanel(new BorderLayout());
mainpanel.add(textpanel, BorderLayout.NORTH);
/*
* graphpanel = new JPanel(); graphpanel.setLayout(new
* BoxLayout(graphpanel, BoxLayout.Y_AXIS));
*/
add(mainpanel, BorderLayout.CENTER);
Display.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Display) {
num_slots = text1.getText();
int slots = Integer.parseInt(num_slots);
num_balls = text2.getText();
int balls = Integer.parseInt(num_balls);
MainPanel pa = new MainPanel(slots, balls);
mainpanel.add(pa);
mainpanel.revalidate();
}
}
});
Start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Start) {
num_slots = text1.getText();
int slots = Integer.parseInt(num_slots);
num_balls = text2.getText();
int balls = Integer.parseInt(num_balls);
MainPanel pa = new MainPanel(slots, balls);
mainpanel.add(pa, BorderLayout.CENTER);
pa.start();
mainpanel.revalidate();
mainpanel.repaint();
}
}
});
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Main frame = new Main();
frame.setTitle("The Galton board");
frame.setSize(1000, 800);
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setAutoRequestFocus(true);
}
}
main panel class contains the chimneys and balls
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;
class MainPanel extends JPanel implements Runnable {
private int num;
private int number_ball;
public static int start_y = 100;
private float ball_x = 385;
private float ball_y = 50;
private float radius = 15;
private static int panel_x = 300;
private static int panel_y = 100;
private int diameter = 20;
private int last_x = 0;
private final static Random generator = new Random();
ArrayList<Balls> list_ball = new ArrayList<Balls>();
private int m_interval = 100;
private Timer m_timer;
public MainPanel() {
}
public MainPanel(int number) {
num = number;
}
public MainPanel(int number, int ball) {
num = number;
number_ball = ball;
for (int i = 1; i <= number_ball; i++)
{
list_ball.add(new Balls());
}
m_timer = new Timer(m_interval, new TimerAction());
}
public int getPanel_y() {
return panel_y;
}
public void start()
{
m_timer.setInitialDelay(250);
m_timer.start();
}
#Override
protected void paintComponent(Graphics g) {
int start_y = 100;
panel_x = 300;
panel_y = 100;
diameter = 20;
last_x = 0;
super.paintComponent(g);
if (num % 2 == 0) {
for (int i = 1; i <= num; i++) {
if ((i % 2) != 0) {
for (int k = 1; k <= num; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
} else if ((i % 2) == 0) {
for (int k = 1; k <= num + 1; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x - 20, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
}
panel_y = panel_y + 40;
panel_x = 300;
}
} else if (num % 2 != 0) {
for (int i = 1; i <= num; i++) {
if ((i % 2) != 0) {
for (int k = 1; k <= num; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
} else if ((i % 2) == 0) {
for (int k = 1; k <= num + 1; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x - 20, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
}
panel_y = panel_y + 40;
panel_x = 300;
}
}
for (int n = 40; n < panel_y - 40; n = n + 40) {
if (num % 2 == 0) {
g.drawLine(panel_x - 50 + n, panel_y - 10, panel_x - 50 + n,
panel_y + 80);
g.drawLine(panel_x, panel_y + 80, panel_x - 50 + n, panel_y + 80);
last_x = panel_x - 50 + n;
} else if (num % 2 != 0) {
g.drawLine(panel_x - 30 + n, panel_y - 10, panel_x - 30 + n,
panel_y + 80);
g.drawLine(panel_x, panel_y + 80, panel_x - 30 + n, panel_y + 80);
last_x = panel_x - 30 + n;
}
}
for (int i = 0; i< list_ball.size(); i++)
{
list_ball.get(i).draw(g);
}
}
class TimerAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i< list_ball.size(); i++)
{
list_ball.get(i).move();
//return;
//m_timer.stop();
repaint();
}
}
Balls Class
import java.awt.geom.Ellipse2D;
import java.util.Random;
import java.awt.*;
public class Balls {
private Ellipse2D.Double thisBall;
private int Ball_x;
private int Ball_y;
public int radius;
public int start_y;
private final static Random generator = new Random();
Mainpanel pa = new Mainpanel();
public Balls()
{
start_y = 100;
Ball_x = 385;
Ball_y = 50;
radius = 15;
}
public void draw(Graphics g)
{
g.setColor(Color.RED);
g.fillOval(Ball_x, Ball_y, radius, radius);
}
public void move()
{
if (Ball_y < pa.getPanel_y() + 65)
{
int direction = generator.nextInt(2);
Ball_y = Ball_y + 5;
if (Ball_y == start_y - 10 && start_y < pa.getPanel_y())
{
if (direction == 0)
{
Ball_x = Ball_x - 20;
}
else Ball_x = Ball_x + 20;
start_y = start_y + 40;
}
System.out.println(Ball_y);
System.out.println(pa.getPanel_y());
}
// Ball_x = Ball_x + 5;
}
}

Create a new logical class, not a GUI class, for your Ball, one that does not extend a JPanel or any Swing component, but rather one that has the logic behind the Ball as well as perhaps a rendering method that accepts a Graphics or Graphics2D object. Then give your drawing JPanel class an ArrayList of these Ball objects, move them in your game loop -- note that I would prefer using a Swing Timer and not a background thread, and then in your JPanel's paintComponent method iterate through the ArrayList of Balls, drawing each Ball by calling its rendering method.
As an aside: all your class names should begin with an upper case letter, and all identifiers other than constants should use camel case, so your mainpanel class should be named MainPanel. I've edited your code prettify the code formatting and have made this change for you.
Aside number 2: your current code has code logic inside of paintComponent. Don't do that as that will mess you up. You don't have full control over when or even if paintComponent will be called.

Related

Multi- threading in Java - trouble with implmenting in program

I created the below bouncing ball program. I'm new to programming in general, but got this working fine. The objective was to have the ball bounce within the frame and to appear in random locations at program start up.
the next thing I am trying to do is to intoduce multiple balls into the frame that bounce around. I'm trying to do this using the Rnnable interface but havent been able to get this working. The Balls can move independently, passing through each other. Each Ball should have its own thread, rather than one thread updating an array of Balls.Below is my attempt but I havent able to get this working.
Any advice would be great.
/*Bounce class*/
import java.awt.Color;
import java.awt.Graphics;
import java.util.concurrent.ThreadLocalRandom;
import javax.swing.JPanel;
public class Bounce2 extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
/*variables*/
int x, y;
int anglex = 1, angley = 1, speed = 10;
int min = 40, max = 760;
public Bounce2() {
min = 60;
max = 740;
}
public void setGenerateRandom (int max, int min) {
x = ThreadLocalRandom.current().nextInt(min, max +1);
y = ThreadLocalRandom.current().nextInt(min, max +1);
run();
}
public void run() {
if (x + anglex < 0) {
anglex = speed;
} else if (x + anglex > getWidth() - 50) {
anglex = -speed;
} else if (y + angley < 0) {
angley = speed;
} else if (y + angley > getHeight() - 50) {
angley = -speed;
}
x = x + anglex;
y = y + angley;
}
public void paint (Graphics g) {
super.paint(g);
Color c = Color.blue;
g.setColor(c);
g.fillOval(x, y, 80, 80);
}
public void random() {
setGenerateRandom(max, min);
}
}
/*Bounce2Test class*/
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class Bounce2Test {
public static void main(String[] args) throws InterruptedException {
{
int num = 0;
String objects;
objects = JOptionPane.showInputDialog("Please enter number of balls!");
num = Integer.parseInt(objects);
// Number of threads
for (int i = 0; i < num; i++) {
Thread object = new Thread(new Bounce2());
object.start();
JFrame frame = new JFrame("Bouncing Ball");
Bounce2 ball = new Bounce2();
frame.add(ball);
frame.setSize(800,800);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ball.random();
while(true) {
ball.run();
ball.repaint();
Thread.sleep(10);
}
}
}
}
}

Dots and boxes - JLabels disapearing

I'm trying to implement the game dots and boxes by using 3 JLabel arrays:
the dots for the game board.
the vertical lines
the horizontal lines
the ide is when you click using MouseInputAdapter to get the coordinates of the mouse the it should check if the coordinates of mouse point are in one of the labels of the verticals or horizontal lines. But when I run the program my JPanel is completly empty. And other times when I run it and it's not empty all the labels just vanish after I click.
package gameframes;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import javax.swing.event.MouseInputAdapter;
import java.awt.Color;
public class LinesAndBoxesFrame extends JFrame {
JLabel[][] dots = new JLabel[8][8];
JLabel[][] herizontalLines = new JLabel[8][7];
JLabel[][] verticallLines = new JLabel[8][7];
public LinesAndBoxesFrame(String title) {
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(620, 640);
setLocationRelativeTo(null);
setVisible(true);
setLayout(null);
JPanel p=new JPanel();
p.setSize(600,600);
add(p);
for (int i = 0; i < dots.length; i++) {
for (int j = 0; j < dots.length; j++) {
dots[i][j] = new JLabel();
dots[i][j].setBounds(20 + i * (20 + 50), 20 + j * (20 + 50), 20, 20);
dots[i][j].setOpaque(true);
dots[i][j].setBackground(Color.red);
p.add(dots[i][j]);
p.repaint();
}
}
for (int i = 0; i < herizontalLines.length; i++) {
for (int j = 0; j < herizontalLines[0].length; j++) {
herizontalLines[i][j] = new JLabel();
herizontalLines[i][j].setBounds(40 + j * (20 + 50), 20 + i * (20 + 50), 50, 20);
herizontalLines[i][j].setOpaque(true);
herizontalLines[i][j].setBackground(Color.green);
herizontalLines[i][j].setVisible(false);
p.add(herizontalLines[i][j]);
p.repaint();
}
}
for (int i = 0; i < verticallLines.length; i++) {
for (int j = 0; j < verticallLines[0].length; j++) {
verticallLines[i][j] = new JLabel();
verticallLines[i][j].setBounds(20 + i * (20 + 50), 40 + j * (20 + 50), 20, 50);
verticallLines[i][j].setOpaque(true);
verticallLines[i][j].setBackground(Color.green);
verticallLines[i][j].setVisible(false);
p.add(verticallLines[i][j]);
p.repaint();
}
}
p.addMouseListener(new MouseInputAdapter() {
int count = 0;
#Override
public void mouseClicked(MouseEvent e) {
int mX = e.getX();
int mY = e.getY();
System.out.println(mX);
System.out.println(mY);
boolean b = false;
for (JLabel[] l : herizontalLines) {
for (JLabel l1 : l) {
b = checkBounds(l1, mX, mY);
if (b) {
l1.setVisible(true);
break;
}
}
}
if (!b) {
for (JLabel[] l : verticallLines) {
for (JLabel l1 : l) {
b = checkBounds(l1, mX, mY);
if (b) {
l1.setVisible(true);
break;
}
}
}
}
System.out.println(b + " metod finished! " + count);
p.revalidate();
p.repaint();
count++;
}
});
// add(p);
// repaint();
p.revalidate();
p.repaint();
}
public boolean checkBounds(JLabel l, int x, int y) {
return (x >= l.getX() && x <= l.getX() + l.getWidth()) && (y >= l.getY() && y <= l.getY() + l.getHeight());
}
public static void main(String[] args) {
new LinesAndBoxesFrame("Dots and Boxes");
}
}
Update:
I just needed to set the layout of my JPanel to null and that fixes it.

Button To Reset The View Of JFrame

I have to write a program that will generate 20 random circles with random radius lengths. If any of these circles intersect with another, the circle must be blue, and if it does not intersect, the color is red. I must also place a button on the JFrame. If this button is pressed, it needs to clear out the JFrame, and generate a new set of 20 circles following the same color rules. I am extremely new to Java Swing and am really stuck. I have everything working except the button. I cannot get a new set of circles to generate. Any help would be greatly appreciated. Thank You.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
setPreferredSize(new Dimension(1000, 800)); // set window size
Random random = new Random();
// Create coordinates for circles
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(700) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
// Add button to run again
JButton btnAgain = new JButton("Run Again");
btnAgain.setBounds(850, 10, 100, 30);
add(btnAgain);
btnAgain.addActionListener(new ButtonClickListener());
// Determine if circles intersect, create circles, color circles
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i != h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.BLUE);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
private class ButtonClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String action = e.getActionCommand();
if(action.equals("Run Again"))
{
new IntersectingCircles();
}
}
}
}
Suggestions:
Give your class a method that creates the random circles and calls repaint()
This method should create the circles and add them into an ArrayList.
Consider using Ellipse2D to represent your circles, and so you'd have an ArrayList<Ellipse2D>.
Call this method in your class constructor.
Call it again in the button's ActionListener.
Never add button's or change the state of your class from within your paintComponent method. This method is for drawing the circles and drawing them only and nothing more. Your way you will be creating the button each time the paintComponent method is called, so you could be potentially needlessly creating many JButtons
and needlessly slowing down your time-critical painting method.
Instead add the button in the constructor.
Be sure to call super.paintComponent(g) in your paintComponent method as its first call. This will clear the old circles when need be.
Also in paintComponent, iterate through the ArrayList of circles, drawing each one.
After some searching on this website, i found what i needed. Everything seems to work now. Thanks.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(1000, 800));
ActionListener runAgain = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent c)
{
frame.getContentPane().add(new IntersectingCircles());
frame.pack();
}
};
JButton btnAgain = new JButton("Run Again");
btnAgain.setBounds(850, 10, 100, 30);
btnAgain.addActionListener(runAgain);
frame.add(btnAgain);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
Random random = new Random();
// Create coordinates for circles
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(700) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// Determine if circles intersect, create circles, color circles
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i != h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.BLUE);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
}
private class ButtonClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
}
Maybe you can have a try...

Frogger Type Game Collision Detection

I need some help figuring out how to capture and store collisions in a frogger game. I've managed to get the game to run fairly smoothly and now want to add collisions to the game. After some research I've found that rectangles seem like a viable option for my game, however, I'm not sure where I should start to actually capture a collision from an "enemy" and a "player". Here is my code so far:
public class myJPanel0 extends JPanel implements KeyListener, ActionListener
//This panel will contain the game
{
JButton menu;
Image myImage;
Graphics g;
myJPanel1 p1;
// Border[] gameBorder = new Border[]{BorderFactory.createTitledBorder("Border types")};
gameOverJPanel gp;
JButton lion = new JButton(new ImageIcon("images/download.jpg"));
JButton yard = new JButton("50 Yardline");
JButton score = new JButton("Touchdown");
JButton start = new JButton("Start");
JButton scoreKeeper = new JButton("Your score is");
JButton lives = new JButton("Lives left = ");
Timer tim;
int delay = 100;
int x = 296;
int y = 685;
int counter = 0;
ButtonObject[] enemies = new ButtonObject[10];
ButtonObject[] enemies1 = new ButtonObject[10];
ImageIcon icon[] = new ImageIcon[10];
public myJPanel0(myJPanel1 informedp1, gameOverJPanel informedgp)
{
super();
setLayout(null);
p1 = informedp1;
gp = informedgp;
setBackground(Color.MAGENTA);
menu = new JButton("Menu");
scoreKeeper.setBounds(16,80,200,55);
lives.setBounds(417, 80,200,55);
lion.setBounds(x,y,40,55);
score.setBounds(16,135,601,55);
yard.setBounds(16,410,601,55);
start.setBounds(16,685,601,55);
menu.setBounds(new Rectangle(250,5,80,30));
add(menu);
add(lives);
add(lion);
add(yard);
add(start);
add(scoreKeeper);
add(score);
setFocusable(true);
addKeyListener(this);
tim = new Timer(delay, this);
tim.start();
for (int i = 0; i <= 3; i++){ // loop that cycles through first half of enemy creation
String text = String.valueOf(i);
int y = 630 - (i * 55);
int x = 16;
enemies[i] = new ButtonObject(text+"??", x, y, 40, 55);
enemies[i].setBounds(new Rectangle(x, y, 40,55));
add(enemies[i]);
}
for (int i = 0; i <= 3; i++){ // second have enemy creation
String text = String.valueOf(i);
int y = 355 - (i * 55);
int x = 16;
enemies1[i] = new ButtonObject(text+"??", x, y, 40, 55);
enemies1[i].setBounds(new Rectangle(x, y, 40,55));
add(enemies1[i]);
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Image myLion = Toolkit.getDefaultToolkit().getImage("images/download.jpg");
g.drawImage(myLion,296,355,40,55,this);
if(p1.myImage1 == 1)
{
super.paintComponent(g);
Image myImage = Toolkit.getDefaultToolkit().getImage("images/snow.jpg");//Place holder for now, we can come up with our own image.
g.drawImage(myImage, 0, 0,680,880, this);
requestFocusInWindow();
}else if(p1.myImage1 == 2)
{
super.paintComponent(g);
Image myImage = Toolkit.getDefaultToolkit().getImage("images/grass.jpg");//Place holder for now, we can come up with our own image.
g.drawImage(myImage, 0, 0,680,880, this);
requestFocusInWindow();
}
else{
super.paintComponent(g);
Image myImage = Toolkit.getDefaultToolkit().getImage("images/stone.jpg");//Place holder for now, we can come up with our own image.
g.drawImage(myImage, 0, 0,680,880, this);
requestFocusInWindow();
}
}
public void keyPressed(KeyEvent evt)
{
System.out.println("Key pressed");
int kk = evt.getKeyCode();
if(kk == evt.VK_LEFT) {x=x-40;}
else if(kk == evt.VK_RIGHT) {x=x+40;}
else if(kk == evt.VK_UP) {y=y-55;}
else if(kk == evt.VK_DOWN) {y=y+55;}
lion.setBounds(x,y,40,55);
System.out.println(x);
System.out.println(y);
if(y <= 135){
counter = counter + 1;
scoreKeeper.setText("Your score is " + counter);
y = 740;
}
}
public void keyReleased(KeyEvent evt) { }
public void keyTyped(KeyEvent evt) { }
public void actionPerformed(ActionEvent event) {
for (int i = 0; i <= 3; i++)
{
enemies[i].move();
}
for (int i = 0; i <= 3; i++)
{
enemies1[i].move();
}
}
}

Java Circle to Circle collision detection

I am making a circle to circle collision detection program. I can get the balls to move around but when the collision is detected, the balls are quite far overlapped. Any suggestions? Thanks in advance!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.lang.Math;
public class ShapePanel extends JPanel{
private JButton button, startButton, stopButton;
private JTextField textField;
private JLabel label;
private Timer timer;
private final int DELAY = 10;
ArrayList<Shape> obj = new ArrayList<Shape>();
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ShapePanel());
frame.pack();
frame.setVisible(true);
}
public ShapePanel(){
JPanel controlPanel = new JPanel();
DrawingPanel dpanel = new DrawingPanel();
controlPanel.setPreferredSize(new Dimension(100,400));
button = new JButton("Add Shape");
startButton = new JButton("Start");
stopButton = new JButton("Stop");
textField = new JTextField(2);
label = new JLabel("Count:");
controlPanel.add(button);
controlPanel.add(label);
controlPanel.add(textField);
controlPanel.add(startButton);
controlPanel.add(stopButton);
add(controlPanel);
add(dpanel);
ButtonListener bListen = new ButtonListener();
button.addActionListener(bListen);
startButton.addActionListener(bListen);
stopButton.addActionListener(bListen);
timer = new Timer(DELAY, bListen);
}
private class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if (e.getSource() == button){
obj.add(new Shape());
if (obj.get(obj.size()-1).y > 200){
obj.get(obj.size()-1).moveY = -obj.get(obj.size()-1).moveY;
}
}else if (e.getSource() == timer){
for (int i = 0; i < obj.size(); i++){
obj.get(i).move();
}
for (int i = 0; i < obj.size(); i++){
for (int j = i + 1; j < obj.size(); j++){
if (Math.sqrt(Math.pow((double)obj.get(i).centerCoordX - (double)obj.get(j).centerCoordX,2)) +
Math.pow((double)obj.get(i).centerCoordY - (double)obj.get(j).centerCoordY,2) <= obj.get(i).radius + obj.get(j).radius){
timer.stop();
}
}
}
}else if (e.getSource() == startButton){
timer.start();
}else if (e.getSource() == stopButton){
timer.stop();
}
repaint();
}
}
private class DrawingPanel extends JPanel{
DrawingPanel(){
setPreferredSize(new Dimension(400,400));
setBackground(Color.pink);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int i = 0; i < obj.size(); i++){
obj.get(i).display(g);
}
}
}
}
import java.awt.*;
import java.util.*;
public class Shape{
public int x, y, width, height, moveX = 1, moveY = 1, centerCoordX, centerCoordY, radius;
private Color colour;
public boolean reverse = false, sameDirection = true;
Random generator = new Random();
public int randomRange(int lo, int hi){
return generator.nextInt(hi-lo)+lo;
}
Shape(){
width = randomRange(30, 50);
if (width % 2 != 0){
width = randomRange(30, 50);
}
height = width;
radius = width/2;
x = randomRange(0, 400-width);
y = randomRange(0, 400-height);
colour = new Color(generator.nextInt(256),generator.nextInt(256),generator.nextInt(256));
}
public void display(Graphics g){
g.setColor(colour);
g.fillOval(x, y, width, height);
}
void move(){
x += moveX;
y += moveY;
centerCoordX = x + width/2;
centerCoordY = y + height/2;
if(x >= 400-width){
moveX = -moveX;
}if(x <= 0){
moveX = -moveX;
}if(y >= 400-height){
moveY = -moveY;
}if (y <= 0){
moveY = -moveY;
}
}
}
So much uncommented code!
The balls are just colliding if their centres are within the sum of the radii. Let r1 and r2 be the ball radii, and x1, y1 the position of the centre of ball1; similarly x2, y2 for ball2.
Measure the square of the distance between the centres as (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1). (Pythagoras).
They have collided if this is less than or equal to (r1 + r2) * (r1 + r2).
The key thing here is that there is no need to compute the square roots which is an expensive computational task.
I'd say it probably due to your circles moving too fast or your time step is too high. Reduce your time step. A better approach is use a physics library like Box2D. Have a look at libgdx, that a java library that has it included.
its discussed a bit in this link
You should check the colision after each move.
for (int i = 0; i < obj.size(); i++)
{
obj.get(i).move();
for (int j = 0; j < obj.size(); j++)
{
if (Math.sqrt(Math.pow((double)obj.get(i).centerCoordX - (double)obj.get(j).centerCoordX,2)) +
Math.pow((double)obj.get(i).centerCoordY - (double)obj.get(j).centerCoordY,2) <= obj.get(i).radius + obj.get(j).radius && i!=j)
{
timer.stop();
}
}
}
You need something like this.
public boolean overlaps (Circle c1, Circle c2) {
float dx = c1.x - c2.x;
float dy = c1.y - c2.y;
float distance = dx * dx + dy * dy;
float radiusSum = c1.radius + c2.radius;
return distance < radiusSum * radiusSum;
}

Categories

Resources