3

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;

    }


  }
}
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
Paldan
  • 395
  • 1
  • 6
  • 16

4 Answers4

3

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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

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

joey.enfield
  • 1,229
  • 8
  • 14
0

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();
         }              
     }
  }
wxyz
  • 709
  • 3
  • 8
0

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;
}
Ben Poulson
  • 3,368
  • 2
  • 17
  • 26