Java圆与圆碰撞检测

3

我正在制作一个圆与圆之间的碰撞检测程序。虽然我可以让球移动,但当检测到碰撞时,球会相互重叠得很远。有什么建议吗?谢谢!

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;

    }


  }
}

4
请参考此答案中对形状碰撞检测的技巧:https://dev59.com/ZGUq5IYBdhLWcg3wV_Ei#14575043 - Andrew Thompson
4个回答

3

太多未注释的代码了!

只有当两个球心距离小于等于半径之和时,它们才会碰撞。设r1和r2为球的半径,x1、y1为球1的中心位置;类似地,x2、y2为球2的中心位置。

用公式 (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) 来测量两个球心之间的距离的平方。(勾股定理)

如果这个值小于或等于 (r1 + r2) * (r1 + r2),则它们已经碰撞了。

关键在于无需计算平方根,这是一项昂贵的计算任务。


0

每次移动后都应该检查碰撞。

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();
         }              
     }
  }

那并不是优化过的。 - Martijn Courteaux

0
你需要类似这样的东西。
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;
}

0
我认为这可能是因为你的圆形移动得太快或者时间步长太高了。减小时间步长是一个更好的方法。更好的方法是使用物理库,比如Box2D。可以看一下libgdx,这是一个包含Box2D的Java库。 在this link中也有一些讨论。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接