球/圆碰撞问题

时间:2013-06-08 16:09:33

标签: java swing collision geometry

我试图让球弹跳,或在碰撞时反转方向。我检查了移动方法中的碰撞。它检查两个球之间是否有碰撞,如果是真的,它会反转速度。 问题在于,偶尔球会相互穿过,较小的球大多数。球会反弹到早期,反弹很晚,卡在一起振动,或者互相穿过。

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

    }
}
}

更新版本:来自J W和ZnW的建议。并添加更多球,以便您可以更清楚地看到问题

public class Balls2{

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


public Balls2(){
    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(350,350,0,0,150,Color.PINK,this));

        balls.add(new Ball(500,0,0,10,20,Color.RED,this));
        balls.add(new Ball(0,500,10,0,20,Color.CYAN,this));
        balls.add(new Ball(500,1000,0,-10,20,Color.ORANGE,this));
        balls.add(new Ball(1000,500,-10,0,20,Color.GREEN,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();
                    ball.checkCollision();
                }       

            }});
        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{
    private int x;
    private int y;
    private int speedX;
    private int speedY;
    private int radius;
    private int height;
    private int width;
    private Color color;
    private 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(){

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


        x += speedX;
        y += speedY;

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

    }
}
}

2 个答案:

答案 0 :(得分:1)

球的移动和球的碰撞不应该在每个球的相同功能中完成。假设你有球A和B即将发生碰撞。球A移动然后检查碰撞,找到一个并反转方向。然后球B移动,当它移动时,它可以在检测到它之前移出碰撞区。然后它检查碰撞并找不到碰撞,并继续朝同一方向前进。

应移动所有球,然后检查是否有任何碰撞(反之亦然 - 它们是等效的)。

所以我会从move()函数中移除球碰撞检查并创建一个新函数(建立在ZnW建议的改进上):

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

然后在actionPerformed函数中添加一个循环来检查碰撞:

for(Ball ball : balls){
    ball.checkCollision();
}

答案 1 :(得分:0)

尝试在所有计算后修改位置。 你有非常“资源成本”的碰撞检查,你应该像这样比较球:

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

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