Circle-Rectangle collision detection (intersection)

前端 未结 24 1702
无人共我
无人共我 2020-11-22 02:55

How can I tell whether a circle and a rectangle intersect in 2D Euclidean space? (i.e. classic 2D geometry)

24条回答
  •  刺人心
    刺人心 (楼主)
    2020-11-22 03:15

    I developed this algorithm while making this game: https://mshwf.github.io/mates/

    If the circle touches the square, then the distance between the centerline of the circle and the centerline of the square should equal (diameter+side)/2. So, let's have a variable named touching that holds that distance. The problem was: which centerline should I consider: the horizontal or the vertical? Consider this frame:

    Each centerline gives different distances, and only one is a correct indication to a no-collision, but using our human intuition is a start to understand how the natural algorithm works.

    They are not touching, which means that the distance between the two centerlines should be greater than touching, which means that the natural algorithm picks the horizontal centerlines (the vertical centerlines says there's a collision!). By noticing multiple circles, you can tell: if the circle intersects with the vertical extension of the square, then we pick the vertical distance (between the horizontal centerlines), and if the circle intersects with the horizontal extension, we pick the horizontal distance:

    Another example, circle number 4: it intersects with the horizontal extension of the square, then we consider the horizontal distance which is equal to touching.

    Ok, the tough part is demystified, now we know how the algorithm will work, but how we know with which extension the circle intersects? It's easy actually: we calculate the distance between the most right x and the most left x (of both the circle and the square), and the same for the y-axis, the one with greater value is the axis with the extension that intersects with the circle (if it's greater than diameter+side then the circle is outside the two square extensions, like circle #7). The code looks like:

    right = Math.max(square.x+square.side, circle.x+circle.rad);
    left = Math.min(square.x, circle.x-circle.rad);
    
    bottom = Math.max(square.y+square.side, circle.y+circle.rad);
    top = Math.min(square.y, circle.y-circle.rad);
    
    if (right - left > down - top) {
     //compare with horizontal distance
    }
    else {
     //compare with vertical distance
    }
    
    /*These equations assume that the reference point of the square is at its top left corner, and the reference point of the circle is at its center*/
    

提交回复
热议问题