简体   繁体   中英

Detecting collision between circle and square

I know this has been asked a lot, but personally, i couldn't find a suitable answer. Pretty much everywhere, the function looks something like:

function rccol(rect, circle){
    var dx = Math.abs(circle.x - (rect.x + rect.width / 2));
    var dy = Math.abs(circle.y - (rect.y + rect.height / 2));

    if(dx > circle.radius + rect.width / 2) return false;
    if(dy > circle.radius + rect.height / 2) return false;

    if(dx <= rect.width) return true;
    if(dy <= rect.height) return true; 

    var dx = dx - rect.width;
    var dy = dy - rect.height
    return((dx * dx + dy * dy) <= (circle.radius * circle.radius));
}

And that works perfectly. The issue is that I'm using it for collision detection in a game, where the circle is the player's collision box, and the square is let's say a wall. I need to be able to determine where the contact occurred so that i can actually prevent the "player" from going into the "wall" so the simple boolean that gets returned, doesn't really work in my use-case.

Having circle center coordinates (cx, cy) , you can calculate squared distance from circle center to rectangle.

dx = Max(Abs(cx - rect.center.x) - rect.width / 2, 0)
dy = Max(Abs(cy - rect.center.y) - rect.height / 2, 0)
SquaredDistance = dx * dx + dy * dy

When circle is outside of rectangle initially, it is possible to remove Max call.

dx = Abs(cx - rect.center.x) - rect.width / 2
dy = Abs(cy - rect.center.y) - rect.height / 2

Also we can remove Abs for known initial position (note - upto moment of sign change!)

if cx >= rect.center.x:
      dx = cx - rect.center.x - rect.width / 2
else:
      dx =  - cx + rect.center.x - rect.width / 2

To avoid a lot od different cases, we can virtually put player in the first quadrant relative to rectangle center and correspondingly change coordinates and velocity components

if cx0 < 0:
   cx0 = - cx0
   vx = -vx
if cy0 < 0:
   cy0 = - cy0
   vy = -vy

To register collision moment, you have to substitute coordinates with parametric equations using start point and velocity vector components (vx, vy)

cx = cx0 + vx * t
cy = cy0 + vy * t

and solve (quadratic) equation for t

SquaredDistance - Radius^2 = 0

(cx0 + vx * t - rect.center.x - rect.width/2)^2 + 
(cy0 + vy * t - rect.center.y - rect.height/2)^2 - 
Radius^2 = 0

Ater that you can get zero (no collision), one (touch event) or two roots (moment of collision and moment of exit).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM