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

javascript - 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.

question from:https://stackoverflow.com/questions/65884620/detecting-collision-between-circle-and-square

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

1 Reply

0 votes
by (71.8m points)

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).


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

...