Search code examples
pythonooppygame

I am new, I have a question about PyGame, OOP and Python in general


I am new to programming , PyGame and OOP especially. I can't figure out how to make a button execute a specific command in PyGame. I tried making a class for a button, and if you look at this code, I am able to execute the hover method/function as an example, but I am struggling to make the game close when I press the exit button. I can't seem to understand how to pass an argument that would make the main_menu be false for when exit is executed and main_game be true when play is executed.

from ColorsAndCoordinates import *

pygame.init()

screen = pygame.display.set_mode((1000, 700))
font = pygame.font.Font("freesansbold.ttf", 42)


class Button:
    main_menu = True

    def __init__(self, color, x, y, width, height, text):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text = text

    def display(self, color):
        self.color = color
        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height))
        text = font.render(self.text, True, red)
        screen.blit(text, (self.x, self.y))

    def hover(self, color):
        mouse = pygame.mouse.get_pos()
        if self.x + self.width > mouse[0] > self.x and self.y + self.height > mouse[1] > self.y:
            Button.display(self, color)

    def clicked(self):
        mouse = pygame.mouse.get_pos()
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            if self.x + self.width > mouse[0] > self.x and self.y + self.height > mouse[1] > self.y:
                pass


play_button = Button(blue, 200, 300, 95, 46, "Play")
exit_button = Button(blue, 700, 300, 95, 46, "Exit")
tutorial_button = Button(blue, 410, 550, 165, 46, "Tutorial")

main_menu = True
main_game = False
while main_menu:

    screen.fill(black)
    play_button.display(blue)
    exit_button.display(blue)
    tutorial_button.display(blue)
    play_button.hover(black)
    exit_button.hover(black)
    tutorial_button.hover(black)

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

    exit_button.clicked()

    pygame.display.update()

Solution

  • There are different solutions for this, for instance polymorphism, an action or an event.
    An obvious and simple solution, is to add an action argument to the the method clicked. The argument is an action function, which is invoked when the button is clicked:

    class Button:
        # [...]
    
        def clicked(self, action = None):
            mouse = pygame.mouse.get_pos()
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                if self.x + self.width > mouse[0] > self.x and self.y + self.height > mouse[1] > self.y:
    
                    if action:
                        action()
    

    Create a function, which changes the states. Consider to use the global statement for the variables in global name space main_menu and main_game:

    def action_exit():
        global main_menu, main_game 
        main_menu = False
        main_game = True
    

    Pass the action to the exit_button.clicked:

    while main_menu:
        # [...]
    
        exit_button.clicked(action_exit)
    

    Furthermore changed Button.display(self, color) to self.display(color) in the method display().

    Complete example:

    import pygame
    from pygame.locals import *
    
    pygame.init()
    
    screen = pygame.display.set_mode((1000, 700))
    font = pygame.font.Font("freesansbold.ttf", 42)
    
    red = (255, 0, 0)
    green = (0, 255, 0)
    blue = (0, 0, 255)
    black = (0, 0, 0)
    
    class Button:
        main_menu = True
    
        def __init__(self, color, x, y, width, height, text):
            self.color = color
            self.x = x
            self.y = y
            self.width = width
            self.height = height
            self.text = text
    
        def display(self, color):
            self.color = color
            pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height))
            text = font.render(self.text, True, red)
            screen.blit(text, (self.x, self.y))
    
        def hover(self, color):
            mouse = pygame.mouse.get_pos()
            if self.x + self.width > mouse[0] > self.x and self.y + self.height > mouse[1] > self.y:
                self.display(color)
    
        def clicked(self, action = None):
            mouse = pygame.mouse.get_pos()
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                if self.x + self.width > mouse[0] > self.x and self.y + self.height > mouse[1] > self.y:
    
                    if action:
                        action()
    
    def action_exit():
        global main_menu, main_game 
        main_menu = False
        main_game = True
    
    play_button = Button(blue, 200, 300, 95, 46, "Play")
    exit_button = Button(blue, 700, 300, 95, 46, "Exit")
    tutorial_button = Button(blue, 410, 550, 165, 46, "Tutorial")
    
    main_menu = True
    main_game = False
    while main_menu:
    
        screen.fill(black)
        play_button.display(blue)
        exit_button.display(blue)
        tutorial_button.display(blue)
        play_button.hover(black)
        exit_button.hover(black)
        tutorial_button.hover(black)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                main_menu = False
    
        exit_button.clicked(action_exit)
    
        pygame.display.update()