Java 球/圆碰撞问题

Java 球/圆碰撞问题,java,swing,collision,geometry,Java,Swing,Collision,Geometry,我试图让球反弹,或者在碰撞时反转方向。我让它检查move方法中的冲突。它检查两个球之间是否有碰撞,如果是真的,它将反转速度。 问题是,有时球只是互相穿过,而较小的球大多是。球要么反弹到早,要么反弹到晚,要么粘在一起振动,要么相互穿过 public class Balls{ public static void main(String[] args){ new Balls(); } public Balls(){ JFrame frame = new JFrame("Ball

我试图让球反弹,或者在碰撞时反转方向。我让它检查move方法中的冲突。它检查两个球之间是否有碰撞,如果是真的,它将反转速度。 问题是,有时球只是互相穿过,而较小的球大多是。球要么反弹到早,要么反弹到晚,要么粘在一起振动,要么相互穿过

public class Balls{

public static void main(String[] args){
    new Balls();
}


public Balls(){
    JFrame frame = new JFrame("Balls");
    frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    frame.setSize(1000,1000);
    frame.add(new ballHolder());
}
public class ballHolder extends JPanel{
    ;
    public  List<Ball> balls = new ArrayList<>();
    public ballHolder(){
//add balls(x,y,speedX,speedY,radius,color,parent)

        balls.add(new Ball(670,180,2,9,20,Color.RED,this));
        balls.add(new Ball(570,380,-8,-9,20,Color.ORANGE,this));
        balls.add(new Ball(170,780,2,2,50,Color.PINK,this));
        balls.add(new Ball(470,680,5,3,50,Color.GREEN,this));
        balls.add(new Ball(270,280,9,7,50,Color.CYAN,this));

        System.out.println("Number of Balls: "+ balls.size());
        Timer timer = new Timer(20, new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                for(Ball ball : balls){
                    ball.move();
                }
                repaint();  
            }});
        timer.start();
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        for(Ball ball : balls){
            ball.paint(g2); 
        }
    }
    //gets list of balls
    public  List<Ball> getBalls(){
        return balls;
    }

}

public class Ball{
    int x;
    int y;
    public int speedX;
    public int speedY;
    int radius;
    int height;
    int width;
    Color color;
    ballHolder parent;
    public Ball(int x,int y,int speedX,int speedY,int radius,Color color,ballHolder parent){
        this.x = x;
        this.y = y;
        this.speedX = speedX;
        this.speedY = speedY;
        this.radius = radius;
        this.color = color;
        this.parent = parent;
        this.height = radius * 2;
        this.width = radius * 2;    
    }
    //moves ball
    public void move(){
        x += speedX;
        y += speedY;
        if(x + width > parent.getWidth()){
             x = parent.getWidth() - width;
            speedX = -speedX;
        }else if (0 > x){ 
            x = 0;
            speedX = -speedX;
        }
        if(y + height > parent.getHeight()){
            y = parent.getHeight() - height;
            speedY = -speedY;
        }else if (0 > y){ 
            y = 0;
            speedY = -speedY;
        }
        //check for ball collision
        for(int i=0;i < parent.getBalls().size();i++){
            for(int j=0;j < parent.getBalls().size();j++){
                if(i != j){
                    if(ballCollision(parent.getBalls().get(i), parent.getBalls().get(j))){
                        System.out.println("Collision");
                        parent.getBalls().get(i).speedX *= -1;
                        parent.getBalls().get(i).speedY *= -1;
                    }
                }
            }
        }

    }
    //checks for collision
    public boolean ballCollision(Ball a, Ball b){
        if((b.x-a.x)*(b.x-a.x) + (a.y-b.y)*(a.y-b.y) <= (a.radius+b.radius)*(a.radius+b.radius)){
            return true;
        }else{
            return false;
        }

    }                   
    private void paint(Graphics g2){
        g2.setColor(color);
        g2.fillOval(x, y, width, height);

    }
}
}
公共类舞会{
公共静态void main(字符串[]args){
新球();
}
公众舞会(){
JFrame=新JFrame(“球”);
frame.setDefaultCloseOperation(关闭时退出frame);
frame.setVisible(true);
框架设置尺寸(10001000);
框架。添加(新球座());
}
公共级别持球人扩展JPanel{
;
public List balls=new ArrayList();
公众持球人(){
//添加球(x、y、速度x、速度、半径、颜色、父对象)
添加(新球(670180,2,9,20,颜色。红色,此));
添加(新球(570380,-8,-9,20,颜色。橙色,此));
添加(新球(170780,2,2,50,颜色。粉红色,此));
添加(新球(470680,5,3,50,颜色。绿色,此));
添加(新球(270280,9,7,50,颜色。青色,此));
System.out.println(“球数:+Balls.size());
计时器计时器=新计时器(20,新ActionListener(){
已执行的公共无效操作(操作事件e){
用于(球:球){
ball.move();
}
重新油漆();
}});
timer.start();
}
公共组件(图形g){
超级组件(g);
图形2d g2=(图形2d)g;
用于(球:球){
球形涂料(g2);
}
}
//获取球的列表
公共列表getBalls(){
回球;
}
}
公共班级舞会{
int x;
int-y;
公共int speedX;
公共卫生服务;
整数半径;
内部高度;
整数宽度;
颜色;
持球人父母;
公共球(整数x,整数y,整数speedX,整数speedY,整数半径,颜色,球座父球){
这个.x=x;
这个。y=y;
this.speedX=speedX;
这个。迅速的=迅速的;
这个半径=半径;
这个颜色=颜色;
this.parent=parent;
该高度=半径*2;
该宽度=半径*2;
}
//移动球
公开作废动议(){
x+=速度x;
y+=快速;
如果(x+width>parent.getWidth()){
x=父级.getWidth()-宽度;
speedX=-speedX;
}如果(0>x){
x=0;
speedX=-speedX;
}
如果(y+height>parent.getHeight()){
y=父级。getHeight()-高度;
迅捷=-迅捷;
}如果(0>y){
y=0;
迅捷=-迅捷;
}
//检查有无碰撞
对于(int i=0;ix){
x=0;
speedX=-speedX;
}
如果(y+height>parent.getHeight()){
y=父级。getHeight()-高度;
迅捷=-迅捷;
}如果(0>y){
y=0;
迅捷=-迅捷;
}
x+=速度x;
y+=快速;
}
公共无效检查冲突(){
对于(int j=0;j如果((b.x-a.x)*(b.x-a.x)+(a.y-b.y)*(a.y-b.y)尝试在所有计算之后修改位置。
而且你有非常“资源昂贵”的碰撞检查,你应该像这样比较球:

 for (int j = 0; j < parent.getBalls().size(); j++)
     if (parent.getBalls().get(j) != this)
          if (ballCollision(parent.getBalls().get(j), this)) {
                 System.out.println("Collision");
                 parent.getBalls().get(j).speedX *= -1;
                 parent.getBalls().get(j).speedY *= -1;
                 speedX *= -1;
                 speedY *= -1;
             }
         }
for(int j=0;j

您只是在比较每个球中的所有球。您应该只比较当前球和另一个球,而不是每次比较所有其他球之间的所有球。

球移动和球碰撞不应该对每个球使用相同的函数。假设您有球A和球B即将碰撞。球A移动,然后检查碰撞,找到一个并反转方向。然后球B移动,当它移动时,它可能会在检测到之前移出碰撞区域。然后它检查碰撞,但没有找到,并继续朝同一方向移动

所有的球都应该移动,然后你应该检查是否有碰撞(反之亦然,它们是等效的)

因此,我将从
move()
函数中删除球碰撞检查,并创建一个新函数(基于ZnW建议的改进):


这是一个很好的改进。但是,更新碰撞中涉及的两个球不起作用,因为两个球都会
 for (int j = 0; j < parent.getBalls().size(); j++)
     if (parent.getBalls().get(j) != this)
          if (ballCollision(parent.getBalls().get(j), this)) {
                 System.out.println("Collision");
                 parent.getBalls().get(j).speedX *= -1;
                 parent.getBalls().get(j).speedY *= -1;
                 speedX *= -1;
                 speedY *= -1;
             }
         }
public void checkCollision(){
    for(int j=0;j < parent.getBalls().size();j++){
        if(parent.getBalls().get(j) != this){
            if(ballCollision(parent.getBalls().get(j), this)){
                System.out.println("Collision");
                speedX *= -1;
                speedY *= -1;
            }
        }
    }
}
for(Ball ball : balls){
    ball.checkCollision();
}