collision between a rect and a circle?

Okay, I’m trying to create a method to handle collisions between a rect and a circle. this is how far I’ve gotten, but now I’m stumped. It only works properly if px and py < the circles center.

Here’s the method


    public boolean col(){
    	float planeAngle = (float) Math.toDegrees(Math.atan2(px - (px + pwidth), -(py - py)));
    	float planeWidth = rotate(px + pwidth,py + pheight, px,py,planeAngle,true);
    	float planeHeight = rotate(px + pwidth,py + pheight, px,py,planeAngle,false);
    	float planeCentX = (planeWidth/2);
    	float planeCentY = (planeHeight/2);
    	
    	float dist = (float) Math.sqrt(Math.pow((bx + (bsize/2)) - planeCentX, 2) + Math.pow(-((by + (bsize/2)) - planeCentY), 2));

    	if(dist <= (bx + (bsize/2)))
    		return true;
    		
    	else
    		return false;
    }

and here is the full source: (requires slick)


import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class ColTest extends BasicGame{

    
	float px = 50;
	float py = 50;
	float pheight = 50;
	float pwidth = 50;
	
	float bx = 200;
	float by = 200;
	float bsize = 200;
	
	float pspeed = 3;
    Input input;
    
    public ColTest()
    {
        super("ColTest");
    }
 
    @Override
    public void init(GameContainer gc)
			throws SlickException {
         
    }

    @Override
    public void update(GameContainer gc, int delta)
			throws SlickException
	{
    	input = gc.getInput();
    	
    	try{	
    		if(input.isKeyDown(Input.KEY_UP))	
        		py-=pspeed;
    		
    		if(input.isKeyDown(Input.KEY_DOWN))	
        		py+=pspeed;
    		
    		if(input.isKeyDown(Input.KEY_LEFT))	
        		px-=pspeed;
    		
    		if(input.isKeyDown(Input.KEY_RIGHT))	
        		px+=pspeed;
    	}
    	
    	catch(Exception e){}
	}
 
    public void render(GameContainer gc, Graphics g)
			throws SlickException
    {	
    		g.drawString("col: " + col(), 10, 10);
    		g.fillRect(px, py, 50, 50);
    		g.fillOval(200, 200, 200, 200);
    }
    
    public boolean col(){
    	float planeAngle = (float) Math.toDegrees(Math.atan2(px - (px + pwidth), -(py - py)));
    	float planeWidth = rotate(px + pwidth,py + pheight, px,py,planeAngle,true);
    	float planeHeight = rotate(px + pwidth,py + pheight, px,py,planeAngle,false);
    	float planeCentX = (planeWidth/2);
    	float planeCentY = (planeHeight/2);
    	
    	float dist = (float) Math.sqrt(Math.pow((bx + (bsize/2)) - planeCentX, 2) + Math.pow(-((by + (bsize/2)) - planeCentY), 2));

    	if(dist <= (bx + (bsize/2)))
    		return true;
    		
    	else
    		return false;
    }
    
    public float rotate(float x, float y, float ox, float oy, float a, boolean b)
    {
         float dst = (float) Math.sqrt(Math.pow(x-ox,2.0)+ Math.pow(y-oy,2.0));

         float oa = (float) Math.atan2(y-oy,x-ox);

         if(b)
         	return (float) Math.cos(oa + Math.toRadians(a))*dst+ox;

         else
         	return (float) Math.sin(oa + Math.toRadians(a))*dst+oy;

    }
    
    public static void main(String[] args)
			throws SlickException
    {
         AppGameContainer app =
			new AppGameContainer( new ColTest() );
 
         app.setShowFPS(false);
         app.setAlwaysRender(true);
         app.setTargetFrameRate(60);
         app.setDisplayMode(800, 600, false);
         app.start();
    }
}

Note, I did not really read your code, I stopped when I realized you were using


-(py - py)

as a clever form of 0 :wink:

However, you can problem take an approach similar to this:

  1. Start off assuming that the circle is completely inside the rectangle
  2. For each side of the rectangle calculate the 2d line that represents its edge.
  3. Compute the signed distance from the center of the circle to the edge’s line, where a positive distance is towards the inside of the box and a negative distance is outside the box (this can be found online somewhere easily enough).
  4. If the distance is < -radius, you know the circle is completely outside of the box (because its not on the inside of all edges).
  5. If the distance is between [-radius, radius], the circle intersects the edge so you can change your assumption to just an intersection
  6. After you’ve checked all planes, you’re either inside or intersecting (since outside would have returned early).

I think this should work pretty well, but there may be some corner cases where it’s possible to get a true intersection when it’s not actually intersecting.

You should know better than double posting.

[LOCKED]

Refer to this topic:
http://www.java-gaming.org/index.php/topic,22432.msg185673.html#msg185673