使用pygame连续捕获鼠标事件

时间:2013-08-28 21:47:00

标签: python multithreading user-interface mouseevent pygame

我正在使用pygame构建一个简单的游戏并拥有以下主循环,其中mouse()是捕获和处理鼠标事件的函数,keyboard()用于键盘事件:

def mainLoop():
    pygame.event.pump()
    keyboard(pygame.key.get_pressed())
    events = pygame.event.get()
    mouse(events)
    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()
            return False
    return True

当玩家点击某个牌时,我有mouse()调用的以下函数:

def objReach(obj, pos):     
    try:
        path = obj.reach(pos, move=False)       # A* (path-finding algorithm)
        for step in path:
            sleep(1.0/obj.speed)
            objMove(obj, step)
    except Exception as e:
        sendMsg(str(e))

问题是,当对象走在路径上时(for循环正在运行),鼠标事件不会被捕获,所以如果玩家在中间点击另一个磁贴,则什么都没有发生。我希望玩家能够改变路径。

我尝试在mainLoop循环中使用for,但它只是部分有效 - 它只捕获MOUSEBUTTONUP事件,而不是UP和DOWN事件,这些都是确定如果玩家只是点击或拖放。这是澄清的mouse()函数:

def mouse(events):
    global clickPos
    global releasePos

    for event in events:
        if event.type == MOUSEBUTTONDOWN:
            clickPos = getPos(pygame.mouse.get_pos())
            # getPos() transforms screen coordinates in game coordinates
        elif event.type == MOUSEBUTTONUP:
            releasePos = getPos(pygame.mouse.get_pos())
            if event.button == MAIN_BUTTON:
                # Simple click
                if clickPos == releasePos:
                    if player.privilege > 1:
                        objMove(player, getPos(pygame.mouse.get_pos()))
                    else:
                        objReach(player, getPos(pygame.mouse.get_pos()))
                # Drag and drop
                else:
                    obj = player.place.matrix[clickPos[0]][clickPos[1]][-1]
                    objThrow(obj, clickPos, releasePos)
            elif event.button == SECONDARY_BUTTON:
                pass        # TODO: ...

我不熟悉多线程,我不认为它应该与pygame一起使用,但这是我唯一能想到的。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

您可以尝试修改对象,使其具有类似objReach列表的内容,而不是使用多线程并直接导致对象在obj函数内移动并阻止主循环。它基本上充当一个队列,其中包含要移动到的每个位置的坐标。

然后,你要做的是当点击鼠标时,使用你的寻路算法找到对象应该走的路径并用它替换队列:

import time

def objReach(obj, pos):     
    try:
        obj.path = obj.reach(pos, move=False)       # A* (path-finding algorithm)
        obj.last_move = time.time()
        obj.move_after = 1   # move every 1 second.
    except Exception as e:
        sendMsg(str(e))

然后,在你的主循环中,每秒一次(使用某种计时器来跟踪1秒过去的时间),让你的对象弹出列表中的下一个坐标并移动到它。

它看起来像这样:

def mainLoop():
    pygame.event.pump()
    keyboard(pygame.key.get_pressed())
    events = pygame.event.get()
    mouse(events)
    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()
            return False

    if time.time() - obj.last_move > obj.move_after:
        obj.last_move = time.time()
        objMove(obj, obj.path.pop())

    return True

这样,使对象移动的代码被重新定位到mainloop中,这样您仍然可以响应所有事件。

如果用户点击新图块,则会自动覆盖该路径,并且主循环将正确执行正确的操作。

如果您正确构建了代码,您甚至可以扩展游戏,以便它可以同时处理多个在磁贴上移动的对象,以不同的速度移动。