Search code examples
pythonfunctionbuttonpygameclick

Pygame button issue in functionality


So I'm creating a menu for a game and I have made a button function. The buttons do work but only sometimes:

  • The first button (2-Player) works first click almost every time
  • The second button (1-Player) works less like maybe every 10 clicks
  • The third button (Scores) is even harder to get to work than the others

This doesn't make sense to me as all buttons use the same function:

def button(msg,x,y,h):
  mouse = pygame.mouse.get_pos()
  click = pygame.mouse.get_pressed()

  pygame.draw.rect(screen, RED, (x,y, BUTTON_WIDTH, h))
  smallText = pygame.font.Font("freesansbold.ttf", 20)
  textSurf, textRect = text_objects(msg, smallText, WHITE)
  textRect.center = ((x+(BUTTON_WIDTH/2)),(y+(h/2)))
  screen.blit(textSurf, textRect)

  for event in pygame.event.get():
    if event.type == pygame.QUIT:
        sys.exit()

    if x+BUTTON_WIDTH > mouse[0] > x and y+h > mouse[1] > y:
      pygame.draw.rect(screen, BRIGHT_RED, (x,y, BUTTON_WIDTH, h))
      screen.blit(textSurf, textRect)
      if click[0] == 1:
        return True

def intro_screen():
  intro = True
  while intro:
    screen.fill(GREEN)
    if button("2-Player",245,145,BUTTON_HEIGHT):
      multiplayer_loop()
    if button("1-Player",245,270,BUTTON_HEIGHT):
      login_screen(True)
    if button("Scores",245,395,40):
      login_screen(False)
    screen.blit(TITLE, (120, 5))

    pygame.display.update()

pygame.init()
intro_screen()

Here is how the menu looks

Any help would be greatly appreciated, thanks.


Solution

  • The issue is the event loop in the button function. Note, pygame.event.get() get all the messages and remove them from the queue.
    So 1 button (mostly the 1st button) will get the events and the other buttons get no events.

    Remove pygame.event.get() from the button. Get the events in the main application loop and pass the list of event to the button function.

    Anyway you would not need the event loop in the button function at all, because you evaluate the state of the buttons by pygame.mouse.get_pressed().
    But, I recommend to use the MOUSEBUTTONDOWN event. See pygame.event.

    def button(events,msg,x,y,h):
        smallText = pygame.font.Font("freesansbold.ttf", 20)
        textSurf, textRect = text_objects(msg, smallText, WHITE)
        textRect.center = button_rect.center
    
        mouse       = pygame.mouse.get_pos()
        button_rect = pygame.Rect(x, y, BUTTON_WIDTH, h)
        hit         = button_rect.collidepoint(mouse)
    
        pygame.draw.rect(screen, BRIGHT_RED if hit else RED, button_rect)
        screen.blit(textSurf, textRect)
    
        if hit:
            for event in events:
                if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                    return True
    
    def intro_screen():
        intro = True
        while intro:
    
            events = pygame.event.get()
            for event in events:
                if event.type == pygame.QUIT:
                    sys.exit()
    
            screen.fill(GREEN)
            if button(events , "2-Player",245,145,BUTTON_HEIGHT):
                multiplayer_loop()
            if button(events , "1-Player",245,270,BUTTON_HEIGHT):
                login_screen(True)
            if button(events , "Scores",245,395,40):
                login_screen(False)
            screen.blit(TITLE, (120, 5))
    
            pygame.display.update()
    

    Note, there should be only 1 call to pygame.event.get()per frame.