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
387 views
in Technique[技术] by (71.8m points)

processing - Circle and Rectangle collision

I have a program in Processing for a bouncing ball and a rectangle. I can get the collision for the sides of the rectangle correct, but I have no idea how to get the corners. This is what I have so far:

int radius = 20;
float circleX, circleY;    //positions
float vx = 3, vy = 3;  //velocities    float boxW, boxH;  //bat dimensions

void setup(){
  size(400,400);
  ellipseMode(RADIUS);
  rectMode(RADIUS);
  circleX = width/4;
  circleY = height/4;
  boxW = 50;
  boxH = 20;
}

void draw(){
  background(0);

  circleX += vx;
  circleY += vy;

  //bouncing off sides
  if (circleX + radius > width || circleX < radius){ vx *= -1; }   //left and right
  if (circleY + radius > height || circleY < radius){ vy *= -1; }  //top and bottom
  if (circleY + radius > height){ 
    circleY = (height-radius)-(circleY-(height-radius)); }  //bottom correction

  //bouncing off bat
  if (circleY + radius > mouseY - boxH && circleX > mouseX - boxW && circleX < mouseX + boxW){ 
      vy *= -1; //top
  }
  if (circleX - radius < mouseX + boxW && circleY > mouseY - boxH && circleY < mouseY + boxH){ 
      vx *= -1; //right
  }
  if (circleY - radius > mouseY + boxH && circleX > mouseX - boxW && circleX < mouseX + boxW){ 
      vy *= -1; //bottom
  }
  if (circleX + radius < mouseX - boxW && circleY > mouseY - boxH && circleY < mouseY + boxH){ 
      vx *= -1; //left
  }

  if ([CORNER DETECTION???]){
    vx *= -1;
    vy *= -1;
  }

  ellipse(circleX,circleY,radius,radius);

  rect(mouseX,mouseY,boxW,boxH);
}

I don't know what to put in the if statement to detect the corner collisions.

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

The problem isn't that you need to detect the corner collision. The problem is that you current collision detection doesn't move the ball to a side when a collision is detected.

Call frameRate(5) in your setup() function to better see what's going on:

bad collision

Notice that the ball intersects the top of the box, so you multiply the vy variable by -1. That causes the circle to start moving up. But the next frame, the circle is still colliding with the rectangle, because it hasn't moved up enough yet. So your code detects that collision, multiples vy by -1 again, and the ball moves back down. Next frame the same thing happens, until the ball eventually stop colliding with the rectangle.

To fix this problem, when you detect a collision, you need to move the ball so that it's no longer colliding with the rectangle in the next frame.

Here is an example of how to do that for the top side:

if (circleY + radius > mouseY - boxH && circleX > mouseX - boxW && circleX < mouseX + boxW) { 
    vy *= -1; //top
    circleY = mouseY-boxH-radius;
}

good collision

You'll have to add similar logic for the other sides, but the general idea is the same: make sure that the ball will not be colliding in the next frame, otherwise it'll keep bouncing on the edge like that.

Edit: Taking a closer look at your collision logic, something is still off: you're only ever checking three sides, when you really should be checking all four sides.

Let's take this one for example:

if (circleY + radius > mouseY - boxH && circleX > mouseX - boxW && circleX < mouseX + boxW){ 
    println("top");  
    vy *= -1; //top
}

You're checking that the ball is below the top of the rectangle, to the right of the left of the rectangle, and to the left of the right of the rectangle. That's going to be true for this case:

no collision

Add a println() statement to each of your if statements (see the example in the if statement above) and notice what happens when the ball is below the paddle, or to the right of the paddle.

You need to refactor your logic so that you're checking all four sides, not just three. If I were you, I'd write a function that takes the next position of the ball and returns a boolean value of true if that position collides with the rectangle. Then you can check before moving the ball on the X and Y axis, which tells you how to bounce. Something like this:

  if (collides(circleX + vx, circleY)) {
    vx*=-1;
  } 
  else {
    circleX += vx;
  }
  if (collides(circleX, circleY + vy)) {
    vy*=-1;
  } 
  else {
    circleY += vy;
  }

This takes the place of your four separate if statements, and it solves your above problem as well.


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

...