philosophical introvert philosophical introvert - 6 months ago 13
Java Question

Why is my collision detection not working properly?

I'm creating the widly-known game Pong and I ran into some collision detection problems: the paddle and the ball collide most of the times but sometimes an odd issue occurs: the collision isn't detected and because of that, the ball gets behind the paddle and not change direction. I can't figure out where's the problem hiding. Any and all help would be appreciated.

Note: edited due to a comment.

GamePanel.java



public class GamePanel extends JPanel implements ActionListener, KeyListener {

Ball ball = new Ball();
Player player = new Player();

private void update() {
checkCollision();
}

@Override
public void actionPerformed(ActionEvent a) {
update();
}

public void checkCollision() {
Rectangle playerRect = player.bounds();
Rectangle ballRect = ball.bounds();
if (playerRect.intersects(ballRect)) {
if (ball.getyVelocity() < 0) {
ball.setxVelocity(5);
ball.setyVelocity(-5);
} else if (ball.getyVelocity() > 0) {
ball.setxVelocity(-5);
ball.setyVelocity(5);
}
}
}

}


Ball.java



public class Ball {

private final int RADIUS = 15;
private final int DIAMETER = RADIUS * 2;

private int x_pos = 250;
private int y_pos = 250;

private int xVelocity = -5;
private int yVelocity = -5;

public void update() {
x_pos += xVelocity;
y_pos += yVelocity;

if (x_pos <= 0 + RADIUS) {
xVelocity = 5;
} else if (x_pos >= Pong.WINDOW_WIDTH - (5 + RADIUS)) {
xVelocity = -5;
}

if (y_pos <= 0 + RADIUS) {
yVelocity = 5;
} else if (y_pos >= Pong.WINDOW_HEIGHT - (15 + DIAMETER)) {
yVelocity = -5;
}
}

public void paint(Graphics g) {
g.setColor(Color.white);
g.fillOval(x_pos - RADIUS, y_pos - RADIUS, DIAMETER, DIAMETER);
}

public Rectangle bounds() {
return (new Rectangle(x_pos - RADIUS, y_pos - RADIUS, DIAMETER, DIAMETER));
}

public int getxVelocity() {
return xVelocity;
}

public int getyVelocity() {
return yVelocity;
}

public void setxVelocity(int xVelocity) {
this.xVelocity = xVelocity;
}

public void setyVelocity(int yVelocity) {
this.yVelocity = yVelocity;
}

}


Player.java



public class Player {

private final int WIDTH = 15;
private final int HEIGHT = 150;

private final int X_POS = 5 + WIDTH / 2;

private int y_pos = Pong.WINDOW_HEIGHT / 2 - HEIGHT / 2;

private int yVelocity = 0;

public void update() {
y_pos += yVelocity;

if (y_pos < 0 + HEIGHT / 2) {
y_pos = 0 + HEIGHT / 2;
} else if (y_pos > Pong.WINDOW_HEIGHT - 25 - HEIGHT / 2) {
y_pos = Pong.WINDOW_HEIGHT - 25 - HEIGHT / 2;
}
}

public void paint(Graphics g) {
g.setColor(Color.white);
g.fillRect(X_POS, y_pos - HEIGHT / 2, WIDTH, HEIGHT);
}

public int getyVelocity() {
return yVelocity;
}

public void setyVelocity(int yVelocity) {
this.yVelocity = yVelocity;
}

public int getY_pos() {
return y_pos;
}

public void setY_pos(int y_pos) {
this.y_pos = y_pos;
}

public int getX_POS() {
return X_POS;
}

public int getWIDTH() {
return WIDTH;
}

public int getHEIGHT() {
return HEIGHT;
}

public Rectangle bounds() {
return (new Rectangle(X_POS, y_pos - HEIGHT / 2, WIDTH, HEIGHT));
}

}

Answer

In your checkCollision method, you have to set the xVelocity back to a positive number. Try this:

public void checkCollision() {
      Rectangle playerRect = player.bounds();
      Rectangle ballRect = ball.bounds();
      if (playerRect.intersects(ballRect)) {
          if (ball.getyVelocity() < 0) {
            ball.setxVelocity(5);
            ball.setyVelocity(-5);
        } else if (ball.getyVelocity() > 0) {
            ball.setxVelocity(5);
            ball.setyVelocity(5);
        }
    }
}

Think about it this way, if the ball is going left and hits the player, you want it to go back to the right. X coordinates go up as they go to the right, so setting the xvelocity to a negative number results in it keep moving through the paddle as if it is not touching it.