The code that checks bouncing is off by a bit. First of all, ball.getCenterX()+ball.getRadius()
is effectively the right side of the ball, and that's the only part that you're comparing to the paddle's location. That means that the effective paddle location is off by an amount equal to the radius of the ball. You can see it in your image - the ball only "bounces" once the far right side of the ball is aligned with the paddle.
Secondly, even after changing that part, your code will still fail in certain conditions. Imagine, for example, that the ball is directly under paddle but has not hit the wall yet. Presumably you want the ball to continue moving downward until it hits the wall, then bounce back upwards. However, with the code you have right now, the ball will immediately start moving upwards again as soon as the paddle is above the ball - according to your boolean conditions, the ball is below the paddle and the x-coordinate is between the paddle's edges, so it should "bounce".
I'm assuming you're a beginner and probably don't want to get into a lot of math, so the simplest way to resolve this problem is to use AABBs (axis-aligned bounding boxes) and test for collision using that logic. Here's an example:
// I'm creating a bunch of variables here because I don't know
// what properties your objects have available.
int ballLeftSide = ball.getCenterX() - ball.getRadius();
int ballRightSide = ball.getCenterX() + ball.getRadius();
int ballTopSide = ball.getCenterY() - ball.getRadius();
int ballBottomSide = ball.getCenterY() + ball.getRadius();
int paddleLeftSide = paddle.getTopLeftX();
int paddleRightSide = paddle.getTopLeftX() + paddle.getWidth();
int paddleTopSide = paddle.getTopLeftY();
int paddleBottomSide = paddle.getTopLeftY() + paddle.getHeight();
bool ballOverlapsPaddle = ((ballLeftSide < paddleRightSide) &&
(ballRightSide > paddleLeftSide) &&
(ballTopSide < paddleBottomSide) &&
(ballBottomSide > paddleTopSide))
// Only change ball direction if the ball hasn't already passed
// the paddle. In this case, "passed" means the ball's center is
// further down than the bottom of the paddle.
if ((ballOverlapsPaddle) && (ball.getCenter() < paddleBottomSide))
ball.setDirectionY(UPWARDS);
That boolean condition that checks for overlaps uses a very simple form of the Separating Axis Theorem (SAT) using axis-aligned bounding boxes (AABBs). Basically, it checks whether two rectangular shapes are colliding. Since one of your shapes is a ball, this method treats it as if it had a rectangular bounding box around it when it does this check.
Now, although this solution is very simple, it does bring up some complications. Since your ball is obviously NOT a rectangle, its effective bounding box is going to extend a bit beyond the actual shape of the ball. That means that you'll have "collisions" even when there don't visually appear to be any, as shown in the example below.
There are of course methods to get around that issue, but that gets a little too detailed and techy for a Q+A format. If you'd like to look into it yourself, this is the tutorial I used when I first learned about collision detection between shapes.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…