人们如何有效地处理重复的事件检查 (python/pygame)?

How do people efficiently handle repetitive event checks (python/pygame)?

这更像是一个好奇的问题,因为我回去并设法做了我想做的事情。标题原本是 'Checking if an ordered tuple is in a tuple of ranges?'

到目前为止,我一直在使用此代码检查鼠标点击 -

pos = pygame.mouse.get_pos()

if pos[0] > X and pos[0] < X2 and pos[1] > Y and pos[1] < Y2:
    #Do this

#Separate function with same XY's
if pos[0] > X and pos[0] < X2 and pos[1] > Y and pos[1] < Y2:
    #Do something else - could be used for mouse hover rather than click.  

我想知道其他人是如何进行按钮检测的,因为有时需要不止一次检查(例如在单独的函数中)。有时我会触发一个外部函数、布尔值或计时器,或者类似的东西。我已经在下面的例子中做到了。但这也可能变得混乱,我觉得必须有更简单的方法。

for event in pygame.event.get():
    if event.type == pygame.MOUSEBUTTONDOWN:
        gp = game.pos
        #Initial gbh declaration
        gbh = game.button_health = range(391, 527), range(179, 253)

        if gp[0] in gbh[0] and gp[1] in gbh[1]:
        player.skillpoints -= 1
        player.health += 10
        player.healthmax += 10

#Separate func.
gp = game.pos
gbh = game.button_health

if gp[0] in gbh[0] and gp[1] in gbh[1]:
    blit(font.render(str(Z), True, BLACK), (X, Y))

如果你有重复的代码,那么你可以把它放到一个函数中,然后在代码所在的地方调用它。这使得以后修改代码变得更容易,因为您只需要在一个地方更改它。测试代码也更容易。

举个例子(我也加了一个Google style docstring):

def collided(pos, X, X2, Y, Y2):
    """Check if a point `pos` collides with an area.

    Args:
        pos (tuple): The point.
        X (int, float): The left coordinate of the area.
        etc.

    Returns:
        bool: True if it collides, otherwise False.
    """
    return pos[0] > X and pos[0] < X2 and pos[1] > Y and pos[1] < Y2


# Call the function and pass the needed arguments.
if collided(pg.mouse.get_pos(), X, X2, Y, Y2):
    print('collision')

由于你的问题被标记为 performance,最好从一句名言开始:

"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%" (D. Knuth, "Structured Programming with go to Statements", emphasize mine)

您确定这会对您的应用程序的全局性能产生影响吗?如果 4 次比较产生影响,我会 非常 感到惊讶。所以我们假设这不是性能问题。

首先注意在Python中可以这样写:

if X < pos[0] < X2 and Y < pos[1] < Y2:
     ....

但还有更重要的一点:弄清楚你正在测试的内容。你将如何说清楚?简单地命名它:

if pos[0] > X and pos[0] < X2 and pos[1] > Y and pos[1] < Y2: 
    # Do this

变成:

if area_contains(X, X2, Y, Y2, pos):
    # Do this

或自定义 class:

area = Area(X, X2, Y, Y2)
if area.contains(pos):
    # Do this

为了清楚起见,即使您只有一项测试,您也应该这样做。函数不仅用于减少重复代码(DRY:不要重复自己),还用于提高可读性。看看这个:

player.skillpoints -= 1
player.health += 10
player.healthmax += 10

为什么不呢:

player.increase_health()

不要只将对象用作结构:它们为您提供了一种方便的方式来表达您正在做的事情,而无需透露实现细节。现在,您可以更改 increase_health 的含义,而无需查找导致它的所有事件。