Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
212 views
in Technique[技术] by (71.8m points)

java - Ball sometimes bounces sometimes doesn't

This code makes the ball bounce around the canvas:

//advance the ball
ball.advance();
//check if ball should bounce off canvas sides
if (ball.getCenterX() + ball.getRadius() > canvas.getWidth())
    ball.setDirectionX(LEFT);
if (ball.getCenterX() - ball.getRadius() < 0)
    ball.setDirectionX(RIGHT);

if (ball.getCenterY() + ball.getRadius() > canvas.getHeight())
    ball.setDirectionY(UPWARDS);
if (ball.getCenterY() - ball.getRadius() < 0)
    ball.setDirectionY(DOWNWARDS);

Looks like this: https://gyazo.com/7b51794a6e5e474b508cf442ddebc8dc

Im trying to make it bounce off the paddle when it hits it and I used this code:

boolean bounceInY = ball.getCenterY()+ ball.getRadius() > paddle.getTopLeftY();
boolean bounceInX = (ball.getCenterX()+ ball.getRadius() > paddle.getTopLeftX()) && (ball.getCenterX()+ ball.getRadius() < paddle.getTopLeftX() + paddle.getWidth());

if (bounceInY && bounceInX)
    ball.setDirectionY(UPWARDS);

The issue im having is that it is inconsistent and sometimes it will bounce properly, sometimes it will go through the paddle before bouncing, and sometimes it will go through the paddle and not bounce off of it at all. Looks like this: https://gyazo.com/d1b5c848290fc23183c9b7296f757a51 I am not sure what I am doing wrong, the code for the ball to bounce off the paddle seems like it should work to me. Any help is appreciated :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

False positive "collision"

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...