rectangle-circle collision check

a naive animation demonstrating collision detection between a circle and a rectangle

by Josh Shields

HTML

<canvas id='canvas' width='400' height='300'></canvas>
<div>
	<label>Solid rectangle
		<input type='checkbox' onclick='demo.set_fill (this.checked);'>
	</label>
        <p>you can drag and drop the ball to another location</p>
        <p>The checkbox will turn the inner rectangle solid, allowing to check the collision detection behaviour change when the circle is inside the rectangle (the ball shoud become red permanently).
</div>

CSS

canvas { background:#ddd; }

JavaScript

function collides (rect, circle, collide_inside)
    {
        // compute a center-to-center vector
		var half = { x: rect.w/2, y: rect.h/2 };
        var center = {
            x: circle.x - (rect.x+half.x),
            y: circle.y - (rect.y+half.y)};
            
        // check circle position inside the rectangle quadrant
        var side = {
            x: Math.abs (center.x) - half.x,
            y: Math.abs (center.y) - half.y};
        if (side.x >  circle.r || side.y >  circle.r) // outside
		    return false; 
        if (side.x < -circle.r && side.y < -circle.r) // inside
            return collide_inside;
		if (side.x < 0 || side.y < 0) // intersects side or corner
            return true;
			
        // circle is near the corner
        return side.x*side.x + side.y*side.y  < circle.r*circle.r;
    }
    
    function bounces (rect, circle)
    {
        // compute a center-to-center vector
		var half = { x: rect.w/2, y: rect.h/2 };
        var center = {
            x: circle.x - (rect.x+half.x),
            y: circle.y - (rect.y+half.y)};
            
        // check circle position inside the rectangle quadrant
        var side = {
            x: Math.abs (center.x) - half.x,
            y: Math.abs (center.y) - half.y};
 //console.log ("center "+center.x+" "+center.y+" side "+side.x+" "+side.y);           
        if (side.x >  circle.r || side.y >  circle.r) // outside
		    return { bounce: false }; 
        if (side.x < -circle.r && side.y < -circle.r) // inside
		    return { bounce: false }; 
		if (side.x < 0 || side.y < 0) // intersects side or corner
		{
			var dx = 0, dy = 0;
		    if (Math.abs (side.x) < circle.r && side.y < 0)
			{
			    dx = center.x*side.x < 0 ? -1 : 1;
			}
		    else if (Math.abs (side.y) < circle.r && side.x < 0)
			{
			    dy = center.y*side.y < 0 ? -1 : 1;
			}
			
            return { bounce: true, x:dx, y:dy };
		}
        // circle is near the corner
        bounce = side.x*side.x + side.y*side.y  <...