我必须在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
提前致谢!
答案 0 :(得分:4)
碰撞检测的问题是众所周知的,所以我想而不是推测我可能会使用着名的搜索引擎搜索工作算法。事实证明,关于矩形重叠的好文献比你想象的要容易得多。在我们继续讨论之前,或许我可以评论一下你对
这样的结构的使用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 +宽度之间,那么对象就会发生冲突”。换句话说,两个范围是否重叠。但你肯定要做很多工作才能找到答案。
另外,仅仅因为两个物体在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
如果您坚持使用这些访问器方法,则必须重新构建代码以包含它们。我已经对1-D重叠功能进行了粗略测试,并且在rect_overlap上完全没有,所以请告诉我 - 告诫lector 。出现了两件事。
对代码进行表面检查可以导致无效低效算法的“优化”,因此有时最好回到第一原则并更仔细地查看算法。
如果使用表达式作为函数的参数,则可以在函数体内按名称使用它们,而无需进行明确的赋值。
答案 1 :(得分:2)
def collide(self, target):
# self left of target?
if x + self.width < target.x:
return False
# self right of target?
if x > target.x + target.width :
return False
# self above target?
if y + self.height < target.y:
return False
# self below target?
if y > target.y + target.height:
return False
return True
类似的东西(取决于你的坐标系统,即y正向上或向下)