0

我试图让球反弹,或在它们碰撞时反转方向。我让它检查移动方法中的碰撞。它检查两个球之间是否发生碰撞,如果是真的,它会反转速度。问题是,有时球只是相互穿过,大部分是较小的球。球要么弹得早,弹得晚,要么粘在一起振动,要么互相穿过。

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

    }
}
}

更新版本:来自 JW 和 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);

    }
}
}
4

2 回答 2

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();
}
于 2013-06-08T20:38:41.290 回答
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;
             }
         }

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

于 2013-06-08T16:22:11.250 回答