DevangSahani
DevangSahani

Reputation: 67

What's the most convenient way to add buttons in pygame with text

Following up my last question, for my school assignment, I am developing a game. My concept includes the uses of buttons in this game so I was wondering what is the most convenient way to add buttons in pygame? Also, if you have suggestions for resources which can help me in cases like this, please let me know. Thanks

Here's my Code:

# Program: Import Library, Pygame, for initialization of this program
import pygame
# Initialize the game engine
pygame.init()

# Define Colours

BLACK    = (   0,   0,   0)
WHITE    = ( 255, 255, 255)
GREEN    = (   0, 255,   0)
RED      = ( 255,   0,   0)
BLUE     = (   0,   0, 255)

display_width = 1080
display_height = 720
size = (display_width, display_height)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("MiniConomy Trivia, for Adults")

# Button Program

class Button:
    def __init__(self, size, text, pos, bgColor=(0, 255, 0), textColor=(0, 0, 0)):
        self.pos  = pos
        self.size = size
        self.text = text
        self.font = pygame.font.Font(pygame.font.get_default_font(), size[1])
        self.textSurf = self.font.render(f"{text}", True, textColor)
        self.button = pygame.Surface((size[0], size[1])).convert()
        self.button.fill(bgColor)

    def render(self, window):
        window.blit(self.button, (self.pos[0], self.pos[1]))
        window.blit(self.textSurf, (self.pos[0]+1, self.pos[1]+5))

    def clicked(self, events):
        mousePos = pygame.mouse.get_pos()#  get the mouse position
        for event in events:
            if self.button.get_rect(topleft=self.pos).collidepoint(mousePos[0], mousePos[1]):
                if event.type == pygame.MOUSEBUTTONDOWN:
                    return True
        return False

# Setting a Title Screen
def text_objects(text, font):
    textSurface = font.render(text, True, BLACK)
    return textSurface, textSurface.get_rect()
largeText = pygame.font.Font('freesansbold.ttf', 90)
 
# Creating a Title Screen
TextSurf, TextRect = text_objects("MiniConomy", largeText)
TextRect.center = (540,150)

# Play Button

button = Button([280,50], "Let's Begin", [380,302])
button2 = Button([280, 50], "Second Button", [380, 302])

#Loop until the user clicks the close button
done = False


# -------- Main Program Loop -----------
while done == False:
    events = pygame.event.get()
    for event in events: # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done = True # Flag that we are done so we exit this loop
 
    # Set the screen background
    screen.fill(BLUE)
    screen.blit(TextSurf, TextRect)

    while True:
    # Button 1 Control
        button.render(screen)
    if button.clicked(events):
        print("Game Logic goes here")
    pygame.display.flip()
    
    button2.render(screen)
    if button2.clicked(events):
        print("Game Logic Here")
    pygame.display.flip()

pygame.quit()
quit()

Upvotes: 1

Views: 519

Answers (1)

user14229433
user14229433

Reputation:

The most convenient way to add a button would be to make a button class. I know you are not using OOP with your code, but taking a class approach would allow you to make multiple buttons with a single class acting as a template for each button.

Lets start by making a class. Fist we will make an init function to initialise all the attribute variables of our button.

class Button:
    def __init__(self, size, text, pos):
        self.pos  = pos
        self.size = size
        self.text = text
        self.font = pygame.font.Font(pygame.font.get_default_font(), size/2)
        self.button = pygame.Surface(size[0], size[1]).convert()

Then we will add methods to our class to give our class some behaviour. We want to render our button, then we want to be able to click our button.

    def render(self, window):
        window.blit(self.button, (self.pos[0], self.pos[1]))
        window.blit(self.textSurf, (self.pos[0]+1, self.pos[1]+5))

    def clicked(self, events):
        mousePos = pygame.mouse.get_pos()#  get the mouse position
        for event in events:
            if self.button.get_rect(topleft=self.pos).collidepoint(mousePos[0], mousePos[1]):
                if event.type == pygame.MOUSEBUTTONDOWN:
                    return True
        return False

With this implemented, your code becomes:

 # Program: Import Library, Pygame, for initialization of this program
import pygame
# Initialize the game engine
pygame.init()

    # Define Colours

BLACK    = (   0,   0,   0)
WHITE    = ( 255, 255, 255)
GREEN    = (   0, 255,   0)
RED      = ( 255,   0,   0)
BLUE     = (   0,   0, 255)

display_width = 1080
display_height = 720
size = (display_width, display_height)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("MiniConomy Trivia, for Adults")


class Button:
    def __init__(self, size, text, pos, bgColor=(255, 255, 255), textColor=(0, 0, 0)):
        self.pos  = pos
        self.size = size
        self.text = text
        self.font = pygame.font.Font(pygame.font.get_default_font(), size[1])
        self.textSurf = self.font.render(f"{text}", True, textColor)
        self.button = pygame.Surface((size[0], size[1])).convert()
        self.button.fill(bgColor)

    def render(self, window):
        window.blit(self.button, (self.pos[0], self.pos[1]))
        window.blit(self.textSurf, (self.pos[0]+1, self.pos[1]+5))

    def clicked(self, events):
        mousePos = pygame.mouse.get_pos()#  get the mouse position
        for event in events:
            if self.button.get_rect(topleft=self.pos).collidepoint(mousePos[0], mousePos[1]):
                if event.type == pygame.MOUSEBUTTONDOWN:
                    return True
        return False
        

# Setting a Title Screen
def text_objects(text, font):
    textSurface = font.render(text, True, BLACK)
    return textSurface, textSurface.get_rect()
largeText = pygame.font.Font('freesansbold.ttf', 100)
 
# Creating a Title Screen
TextSurf, TextRect = text_objects("MiniConomy", largeText)
TextRect.center = (540,150)

# Play Button

button = Button([250, 50], "A button", [50, 50])

#Loop until the user clicks the close button
done = False

# -------- Main Program Loop -----------
while done == False:
    events = pygame.event.get()
    for event in events: # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done = True # Flag that we are done so we exit this loop
 
    # Set the screen background
    screen.fill(BLUE)
    screen.blit(TextSurf, TextRect)
    button.render(screen)
    if button.clicked(events):
        print("Your game start logic goes here")
    pygame.display.flip()

Now obviously, there is a lot of potential to add extra features to our button class, like color changing when mouse is over the button and things like that. Just to show you the benefits of using a class. Now if you want another button, you can simply make another instance of button class

anotherButton = Button([300, 500], "Second Button", [500, 500])

and in main loop call:

while True:
   anotherButton.render(screen)
   anotherButton.clicked(events)

And BOOM, you have a second button. Hope i could help.


Edit: Answer to the difficulties you were having. Couple of things.

First, Both buttons are in the same position. Change that.

button = Button([280,50], "Let's Begin", [380,302])
button2 = Button([280, 50], "Second Button", [380, 302]) 

Third argument is position and as you can see, they are the same.

Second, You already have a while True loop so there is no reason why you should add another while True loop. Just use the first while loop, that is why it is called a game loop

Third, You call pygame.display.flip() twice. This function is responsible for updating the screen every frame. Calling it twice means you are trying to update it twice every frame, which can cause unwanted problems.

while not done:
    events = pygame.event.get()
    for event in events: # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done = True # Flag that we are done so we exit this loop
 
    # Set the screen background
    screen.fill(BLUE)
    screen.blit(TextSurf, TextRect)

    # Button 1 Control
    button.render(screen)
    if button.clicked(events):
        print("Game Logic goes here")
    
    button2.render(screen)
    if button2.clicked(events):
        print("Game Logic Here")
    pygame.display.flip()

Upvotes: 2

Related Questions