Search code examples
pythonpython-3.xpygame

Pygame doesn't always register mouse click


So I'm programming this game with Python and Pygame and tried making a menu with clickable buttons. I've wrote this code:

while running:
    click = False
    for event in pygame.event.get():
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                click = True

    window.fill((0, 0, 0))

    button = pygame.Rect(30, 45, 280, 60)
    pygame.draw.rect(window, (52, 235, 177), button1, border_radius=20)
    window.blit(
        (font.render('Start Game', True, (255, 255, 255))), (50, 50))

    if click:
        if button1.collidepoint(pygame.mouse.get_pos()):
            main()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            running = False

    pygame.display.update()

But for some reason Pygame often doesn't register clicking. Sometimes it works on the first try, sometimes I have to click a button like 20 times to make it work. Does anybody have an Idea how to fix that?


Solution

  • The issue is caused, because you have multiple event loops. See pygame.event.get() get all the messages and remove them from the queue. See the documentation:

    This will get all the messages and remove them from the queue. [...]

    If pygame.event.get() is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.

    Get the events once per frame and use them in multiple loops (or pass the list of events to functions and methods where they are handled):

    while running:
        click = False
    
        event_list = pygame.event.get()
        for event in event_list:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    click = True
    
        window.fill((0, 0, 0))
    
        button = pygame.Rect(30, 45, 280, 60)
        pygame.draw.rect(window, (52, 235, 177), button1, border_radius=20)
        window.blit(
            (font.render('Start Game', True, (255, 255, 255))), (50, 50))
    
        if click:
            if button1.collidepoint(pygame.mouse.get_pos()):
                main()
    
        for event in event_list:
            if event.type == pygame.QUIT:
                pygame.quit()
                running = False
    
        pygame.display.update()
    

    Or handle all the events in one loop:

    while running:
        click = False
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                running = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    click = True
    
        window.fill((0, 0, 0))
    
        button = pygame.Rect(30, 45, 280, 60)
        pygame.draw.rect(window, (52, 235, 177), button1, border_radius=20)
        window.blit(
            (font.render('Start Game', True, (255, 255, 255))), (50, 50))
    
        if click:
            if button1.collidepoint(pygame.mouse.get_pos()):
                main()
    
        pygame.display.update()