【问题标题】:Detecting Rectangle collision with a Circle检测与圆的矩形碰撞
【发布时间】:2014-09-03 20:27:30
【问题描述】:

我有一个中心点 (Center_X, Center_Y) 的圆,我正在检测一个矩形是否落入它的半径 (Radius)。我将如何能够执行此任务?我试过使用

if (X - Center_X)^2 + (Y - Center_Y)^2 < Radius^2:
        print(1)

然后我尝试画一个圆圈来适应这个区域:

Circle = pygame.draw.circle(Window, Blue, (Center_X, Center_Y), Radius, 0)

但它似乎没有排队。是不是我做错了什么?

【问题讨论】:

  • XY 是什么?
  • X 和 Y 是敌人的中心点 (EnemyCenter_X, EnemyCenter_Y)
  • 矩形定义了四个角点,所以一般来说,你需要确保它们都在圆内。
  • @martineau 检查 4 个点中的任何一个在圆内都不足以进行碰撞检查。
  • 这不是stackoverflow.com/questions/401847/…的复制品吗?

标签: python pygame collision-detection geometry


【解决方案1】:

这是我在我的 cmets 中描述的内容,以及迈克尔安德森在评论中指出的对更大矩形内的圆形情况的正确处理的更改:

import math

def collision(rleft, rtop, width, height,   # rectangle definition
              center_x, center_y, radius):  # circle definition
    """ Detect collision between a rectangle and circle. """

    # complete boundbox of the rectangle
    rright, rbottom = rleft + width/2, rtop + height/2

    # bounding box of the circle
    cleft, ctop     = center_x-radius, center_y-radius
    cright, cbottom = center_x+radius, center_y+radius

    # trivial reject if bounding boxes do not intersect
    if rright < cleft or rleft > cright or rbottom < ctop or rtop > cbottom:
        return False  # no collision possible

    # check whether any point of rectangle is inside circle's radius
    for x in (rleft, rleft+width):
        for y in (rtop, rtop+height):
            # compare distance between circle's center point and each point of
            # the rectangle with the circle's radius
            if math.hypot(x-center_x, y-center_y) <= radius:
                return True  # collision detected

    # check if center of circle is inside rectangle
    if rleft <= center_x <= rright and rtop <= center_y <= rbottom:
        return True  # overlaid

    return False  # no collision detected

【讨论】:

  • 考虑一个大盒子里面的一个小圆圈。这将返回 false。
  • 现在你也错过了一个小圆的中心正好在盒子的一个边缘之外的情况,(因此在一个边缘上有两个交叉点,但不包括顶点。)
  • @Michael:你说的小姐是什么意思?
  • 也许 also 是错误的,“你仍然没有检测到...”的情况可能会更准确
  • @Michael:感谢您的澄清。至于新的失败案例,虽然可能可以添加代码来处理它,但此时我认为更好的做法是使用问题Circle-Rectangle collision detection (intersection) 的答案之一。
【解决方案2】:

对于这种碰撞检测,您有两个常用选项。

首先是了解两个 2D 物体碰撞的方式。

  1. 一个顶点可以在另一个里面
  2. 他们的两边可以交叉(即使认为里面没有真相)
  3. 一个可以完全在另一个内部。

从技术上讲,案例 1. 只有在案例 2. 也发生时才会发生,但它通常是一种更便宜的检查。 在检查两个对象顶点的情况下,案例 1 也检查案例 3。

我会这样进行。 (按便宜的顺序排列)

  1. 检查它们的边界框是否相交。
  2. 检查正方形的任何顶点是否在内部
  3. 检查圆心是否在矩形内
  4. 检查圆 - 边缘相交。

第二种也是更通用的方法是基于乘积/形状扩展的概念。 此操作允许您将交集问题转换为点包含问题。

在这种情况下,圆形/矩形框的交点可以替换为圆角矩形中的点检查。

【讨论】:

    【解决方案3】:

    使用Shortest distance between a point and a line segment 中的dist 函数

    import math
    
    def dist(p1, p2, c): 
        x1,y1 = p1
        x2,y2 = p2
        x3,y3 = c
        px = x2-x1
        py = y2-y1
    
        something = px*px + py*py
    
        u =  ((x3 - x1) * px + (y3 - y1) * py) / float(something)
    
        if u > 1:
            u = 1
        elif u < 0:
            u = 0
    
        x = x1 + u * px
        y = y1 + u * py
    
        dx = x - x3
        dy = y - y3
    
        dist = math.sqrt(dx*dx + dy*dy)
    
        return dist
    

    这是一个测试:

    rect = [[0. ,  0. ],
           [ 0.2,  1. ],
           [ 2.2,  0.6],
           [ 2. , -0.4]]
    
    c = 0.5, 2.0
    r = 1.0
    
    distances = [dist(rect[i], rect[j], c) for i, j in zip([0, 1, 2, 3], [1, 2, 3, 0])]
    print distances
    print any(d < r for d in distances)
    

    输出:

    [1.044030650891055, 1.0394155162323753, 2.202271554554524, 2.0592194189509323]
    False
    

    剧情如下:

    【讨论】:

    • 正如@Michael Anderson 向我指出的那样:考虑一个完全在一个大盒子内的小圆圈。计算出的任何距离都不会小于半径,因此在这种情况下,您的方法也将返回 False。此外使用&lt; r 意味着触摸不会被视为碰撞。
    • 我明白了,要检测圆心是否在矩形中,您可以从这里使用point_in_poly()stackoverflow.com/questions/16625507/…
    • 检测矩形中的点不需要point_in_poly() 的一般性,因为在pygame 中它们都是直立的。这种甚至检测失败的情况是,一个小圆圈的中心正好在盒子的一个边缘之外,但仍然在(通常)两个点处与它相交。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 2010-09-28
    • 2023-01-26
    • 2014-02-07
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    相关资源
    最近更新 更多