我有一个矩形坐标列表,我正在迭代以测试每个坐标的碰撞。列表如下:self.rectangle_list = [(200, 30, 100, 10), (200, 60, 100, 10), (200, 90, 100, 10), (200, 120, 100, 10), (200, 150, 100, 10)]
。我的for循环代码如下。
mouse_x, mouse_y = event_obj.pos # mouse_x, mouse_y are the coordinates of the mouse.
for rects in self.rectangle_list:
x, y, w, h = rects
if x <= mouse_x <= x + w and y <= mouse_y <= y + h:
self.hovering = True
else:
self.hovering = False
print(self.hovering)
当我打印出self.hovering
时,唯一一次更改为True的时候是鼠标光标位于列表中最后一个矩形的坐标中。
当我在self.hovering
语句下移动if
时它会起作用,但在self.hovering
条件不符合时,永远不会将if
设置回False。
重现问题的示例代码如下:
import pygame as pg
class RenderRects:
def __init__(self, surface, rects_to_render=0):
self.surface = surface
self.rects_to_render = rects_to_render
self.rectangle_list = []
self.hovering = False
def render_rects(self):
y_padding = 0
for rects in range(self.rects_to_render):
y_padding += 30
menu_items_rect = (200, y_padding, 100, 10)
pg.draw.rect(self.surface, (255, 0, 0), menu_items_rect)
if len(self.rectangle_list) > 5:
del self.rectangle_list[4:]
self.rectangle_list.append(menu_items_rect)
def check_for_rect_collision(self, event_obj):
#-----------------Where problem is-----------#
mx, my = event_obj.pos
for rects in self.rectangle_list:
x, y, w, h = rects
if x <= mx <= x + w and y <= my <= y + h:
self.hovering = True
else:
self.hovering = False
print(self.hovering)
#-----------------Where problem is-----------#
def update_rects(self, event_obj):
if event_obj.type == pg.MOUSEMOTION:
self.check_for_rect_collision(event_obj)
def main():
WIDTH = 800
HEIGHT = 600
display = pg.display.set_mode((WIDTH, HEIGHT))
R = RenderRects(display, rects_to_render=5)
running = True
while running:
for e in pg.event.get():
if e.type == pg.QUIT:
running = False
pg.quit()
quit()
R.update_rects(e)
display.fill((255, 255, 255))
R.render_rects()
pg.display.flip()
if __name__ == '__main__':
main()
答案 0 :(得分:4)
在循环中为{em>列表中的每个矩形设置self.hovering
。这意味着,在循环之后,self.hovering
的值对应于&#34;悬停状态&#34;只有最后矩形。
我认为你想在循环之前设置self.hovering = False
,如果其中一个矩形符合你的条件,在循环中将它设置为True
。这样,只有当您的矩形中至少有一个符合您的条件时,self.hovering == True
才会成立。
这是一个简单的问题示例:
numbers = [2,3,4]
contains_odd = False
for number in numbers:
if number % 2 == 0:
contains_odd = False # this is wrong!
else:
contains_odd = True
# contains_odd == (numbers[2] % 2 == 1) == False
解决方案是:
numbers = [2,3,4]
contains_odd = False
for number in numbers:
if number % 2 == 1:
contains_odd = True
# contains_odd == True
答案 1 :(得分:2)
您的if
声明存在问题:
if x <= mouse_x <= x + w and y <= mouse_y <= y + h:
self.hovering = True
您不能像在x <= mouse_x <= x + w
中那样链接小于/大于。这真的被翻译成:
if x <= (mouse_x <= x + w) ....
自True == 1
和False == 0
以来,这意味着如果mouse_x <= x + w
为True
,则x <= (mouse_x <= x + w)
真正成为x <= 1
修改 - 添加了其他问题说明 (感谢Michael Hoff建议)
你的循环也有问题。在循环中,每个矩形对的 ,设置变量self.hovering
。这意味着您将使用当前矩形的状态不断覆盖self.hovering
的值 - 而不是任何矩形正在悬停。
相反,既然你关心self.hovering
是永远 True
,你应该只设置True
案例中的值:
self.hovering = False # assume it's not hovering at first
for rects in self.rectangle_list:
x, y, w, h = rects
if x <= mouse_x and mouse_x <= x + w and y <= mouse_y and mouse_y <= y + h:
self.hovering = True # now it will always be True
虽然这解决了循环问题,但它仍然有点效率低下,因为即使找到一个产生self.hovering = True
的对,它也会继续循环对。当你找到一个好的&#34;时停止循环。对,您可以使用break
,它只是过早地结束循环。
self.hovering = False # assume it's not hovering at first
for rects in self.rectangle_list:
x, y, w, h = rects
if x <= mouse_x and mouse_x <= x + w and y <= mouse_y and mouse_y <= y + h:
self.hovering = True # now it will always be True
break # exit the loop, since we've found what we're looking for
答案 2 :(得分:1)
代码遍历列表并且每个步骤后self.hovering都会发生变化。因此,最后一个矩形确定打印哪个值,因为它是影响它的唯一值,因为打印函数被称为循环的外部。
更新:
如果你希望它是真的,如果任何的矩形适合,你可以使用:
any([x <= mouse_x <= x + w and y <= mouse_y <= y + h for x,y,w,h in self.rectangle_list])
Any是一个内置函数,它被赋予一个可迭代的参数。只要iterable中的任何值为True,它就返回True,否则返回False。在这种情况下,给出一个由所谓的列表推导创建的列表。列表理解等同于以下内容:
lis = []
for x, y, w, h in self.rectangle_list:
lis.append(x <= mouse_x <= x + w and y <= mouse_y <= y + h)
但是,它不需要先创建一个空列表,因此更紧凑。