Skip to main content
 首页 » 编程设计

python之碰撞检测如何

2025年05月04日17cmt

我必须在collide类中编写一个Rectangle方法,该类将另一个Rectangle对象作为参数,如果它与执行该方法的矩形碰撞,则返回True,如果没有,则返回False。我的解决方案是使用一个for循环,该循环遍历一个矩形中的x和y的每个值以查看其是否落在另一个矩形中,但是我怀疑这样做的方式可能更有效或更优雅。这是方法(我认为所有名称都很容易解释,只要问是否不清楚):

def collide(self,target): 
    result = False 
    for x in range(self.x,self.x+self.width): 
        if x in range(target.get_x(),target.get_x()+target.get_width()): 
            result = True 
    for y in range(self.y,self.y+self.height): 
        if y in range(target.get_y(),target.get_y()+target.get_height()): 
            result = True 
    return result 


提前致谢!

请您参考如下方法:

碰撞检测的问题是一个众所周知的问题,因此我认为而不是推测我可能会使用一个著名的搜索引擎来搜索一种有效的算法。事实证明,关于矩形重叠的优质文献比您想像的要难得多。在我们继续之前,也许我可以评论一下您对诸如以下结构的使用

if x in range(target.get_x(),target.get_x()+target.get_width()): 


Python的功劳是,这样一个显而易见的想法实际上按预期成功了。您可能没有意识到的是(无论如何,在Python 2中)每次使用range()都会创建一个列表(在Python 3中,它将创建一个生成器并对其进行迭代;如果您不知道那意味着什么,请接受在计算方面要好一些)。我怀疑你可能的意思是

if target.get_x() <= x < target.get_x()+target.get_width(): 


(我正在使用开放时间间隔测试来反映您对 range()的使用)这具有将N个相等比较替换为两个链接比较的优点。通过相对简单的数学运算(将比较中的每一项减去 target.get_x()),我们将其转换为

if 0 <= x-target.get_x() < target.get_width(): 


不要忽略消除此类冗余方法调用的价值,尽管通过赋值保存评估表达式以供将来参考通常更简单。

当然,经过严格的审查之后,我们必须重新焕发活力

for x in range(self.x,self.x+self.width): 


这在x上设置了上下边界,并且对于x的所有值,您编写的不等式必须为false。但是,值得探索超出代码范围的算法。因为内部测试可能已经完成的任何光照创建现在都重复了很多次(准确地说,是对象的宽度)。我以释义的自由

for x in range(self.x,self.x+self.width): 
    if x in range(target.get_x(),target.get_x()+target.get_width()): 
        result = True 


伪代码:“如果self.x和self.x + self.width之间的任何x位于目标的x与目标的x + width之间,则对象正在碰撞”。换句话说,两个范围是否重叠。但是,您一定会做很多工作来找出答案。

而且,仅因为两个对象在x维度上碰撞并不意味着它们在空间上碰撞。实际上,如果它们也未在y维度上发生碰撞,则对象将不相交,否则,您将这些矩形视为发生碰撞:

+----+ 
|    | 
|    | 
+----+ 
 
  +----+ 
  |    | 
  |    | 
  +----+ 


因此,您想知道它们是否在两个尺寸上都发生了碰撞,而不仅仅是一个尺寸。理想情况下,将定义一维碰撞检测(到现在为止我们几乎已经有了...),然后将其应用于这两个维度。我还希望可以通过简单的属性访问来替换那些访问器函数,并且我的代码从现在开始就假设是这种情况。

到目前为止,可能是时候快速浏览 this YouTube video中的原理了,它使几何图形相对清晰,但根本无法很好地表达公式。只要您使用相同的坐标系,它就会很好地说明原理。如果A的左侧在B的左侧和右侧之间,则基本上两个对象A和B水平重叠。如果B的右边在A的左边和右边之间,它们也会重叠。这两个条件都可能成立,但是在Python中,您应该考虑使用关键字 or以避免不必要的比较。

因此,让我们定义一维重叠函数:

def oned_ol(aleft, aright, bleft, bright): 
    return (aleft <= bright < aright) or (bleft <= aright < bright) 


我要作弊并在两个维度上都使用它,因为函数内部不知道我要用哪个维度的数据来调用它。如果我是正确的,则应采用以下公式:

def rect_overlap(self, target): 
    return oned_ol(self.x, self.x+self.width, target.x, target.x+target.width) \ 
        and oned_ol(self.y, self.y+self.height, target.y, target.y+target.height 


如果您坚持使用这些访问器方法,则必须重新广播代码以包括它们。我已经对一维重叠函数进行了粗略的测试,而对rect_overlap则根本不做任何测试,所以请让我知道-警告。出现两件事。


对代码进行肤浅的检查可能会导致对毫无希望的效率低下的算法进行“优化”,因此有时最好返回第一原理并更仔细地研究您的算法。
如果将表达式用作函数的参数,则可以通过名称在函数体内使用它们,而无需进行显式分配。