我试图让球弹跳,或在碰撞时反转方向。我检查了移动方法中的碰撞。它检查两个球之间是否有碰撞,如果是真的,它会反转速度。 问题在于,偶尔球会相互穿过,较小的球大多数。球会反弹到早期,反弹很晚,卡在一起振动,或者互相穿过。
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);
}
}
}
答案 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;
}
}
只是你在比较每个球的所有球。你应该只比较当前的球和另一个球,但不是每次都比较所有其他球之间的所有球。