简体   繁体   English

在if语句永远不会为False的情况下设置为True的变量

[英]variable that is set to True in if statement never becomes False

I have a list of rectangles coordinates, that I'm iterating over to test for collisions with each one. 我有一个矩形坐标列表,正在迭代以测试与每个坐标的碰撞。 The list is Like so: self.rectangle_list = [(200, 30, 100, 10), (200, 60, 100, 10), (200, 90, 100, 10), (200, 120, 100, 10), (200, 150, 100, 10)] . 列表如下所示: self.rectangle_list = [(200, 30, 100, 10), (200, 60, 100, 10), (200, 90, 100, 10), (200, 120, 100, 10), (200, 150, 100, 10)] My code for the for loop is below. 我的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)

When I print out self.hovering , The only time It changes to True is when The mouse cursor is in the coordinates of the very last rectangle in the list. 当我打印出self.hovering ,只有当鼠标光标在列表中最后一个矩形的坐标中时,它才会变为True。

When I move self.hovering under the if statement it works, but never sets self.hovering back to False while the if condition is not meet. 当我在if语句下移动self.hovering ,它可以工作,但是在不满足if条件时,请勿将self.hovering设置回False。

example code to reproduce the problem is bellow: 重现该问题的示例代码如下:

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()

You set self.hovering inside the loop for every rectangle in the list. 您可以为列表中的每个矩形在循环内设置self.hovering This means, after the loop the value of self.hovering corresponds to the "hovering state" of only the last rectangle. 这意味着,在循环之后, self.hovering的值self.hovering对应于最后一个矩形的“悬停状态”。

I think you want to set self.hovering = False before the loop and in the loop set it to True if one of the rectangles matches your condition. 我认为您想在循环之前设置self.hovering = False ,如果其中一个矩形符合您的条件,则在循环中将其设置为True This way, self.hovering == True holds only if at least one of your rectangles matches your condition. 这样, self.hovering == True仅在至少一个矩形与您的条件匹配时才成立。

This is a simplistic example for your problem: 这是您的问题的一个简单示例:

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

The solution would be: 解决方案是:

numbers = [2,3,4]
contains_odd = False
for number in numbers:
    if number % 2 == 1:
        contains_odd = True

# contains_odd == True

Your if statement has a problem: 您的if陈述式有问题:

if x <= mouse_x <= x + w and y <= mouse_y <= y + h:
                self.hovering = True

You can't chain less than/greater than as you do in: x <= mouse_x <= x + w . 您不能像在以下情况中那样小于/大于: x <= mouse_x <= x + w This really gets translated to: 这确实可以转换为:

if x <= (mouse_x <= x + w) ....

And since True == 1 and False == 0 , this means that if mouse_x <= x + w is True , x <= (mouse_x <= x + w) really becomes x <= 1 并且由于True == 1False == 0 ,所以这意味着如果mouse_x <= x + wTrue ,则x <= (mouse_x <= x + w)实际上变为x <= 1


Edit -- Added additional problem explanation (credit to Michael Hoff for the suggestion) 编辑-添加了其他问题解释 (建议给迈克尔·霍夫Michael Hoff

You also have a problem with your loop. 您的循环也有问题。 In the loop, for every rectangle pair , you set the variable self.hovering . 在循环中, 为每个矩形对设置变量self.hovering This means that you are continuously overwriting the value of self.hovering with the status of the current rectangle --- not if any of the rectangles are hovering. 这意味着您将不断用当前矩形的状态覆盖self.hovering的值---如果任何一个矩形都在悬停,则不会。

Instead, since you care if self.hovering is ever True , you should only set the value in the True case: 相反,因为你不在乎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

While this solves the loop issue, it's still a little bit inefficient, as it will continue looping over the pairs even after you find one that makes self.hovering = True . 虽然这解决了循环问题,但仍然有点低效,因为即使您找到使self.hovering = True的对,它仍将继续循环对。 To stop looping when you find a "good" pair, you can use break , which just prematurely ends a loop. 要在找到“好”对时停止循环,可以使用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

The code is iterating through the list and self.hovering changes after each step. 代码在列表中进行迭代,并且在每个步骤之后self.hovering都会更改。 Therefore, the last rectangle determines which value is printed since its the only one influencing it since the print function is called outside of the loop. 因此,最后一个矩形决定打印哪个值,因为它是唯一影响它的值,因为在循环之外调用了打印功能。

Update : 更新
If you want it to be True if any of the rectangles fits, you can use: 如果希望在任何矩形适合的情况下将其设置为True,则可以使用:

any([x <= mouse_x <= x + w and y <= mouse_y <= y + h for x,y,w,h in self.rectangle_list])

Any is a built-in function that is given an iterable as argument. Any是一个内置函数,可将其作为参数进行迭代。 It returns True whenever any value within the iterable is True, otherwise False. 只要iterable中的任何值为True,否则返回True。 In this case, it is given a list created by a so called list comprehension. 在这种情况下,给它一个由所谓的列表理解创建的列表。 The list comprehension is equivalent to the following: 列表理解等效于以下内容:

lis = []
for x, y, w, h in self.rectangle_list:
    lis.append(x <= mouse_x <= x + w and y <= mouse_y <= y + h)

However, it does not require to create an empty list first and is therfore more compact. 但是,它不需要先创建一个空列表,因此更加紧凑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM