Buttons under the pause button do not execute their code when pressed

Joined
Aug 7, 2024
Messages
1
Reaction score
0
I'm trying to add a basic feature in my game where if I press the pause button, it stops updating other game elements such as the player and obstacles and buttons such as resume, restart and main menu appear on your screen. I was able to make it work, but my problem now is that when I press any of the three buttons, they do not execute the code under them. Any form of help would be appreciated.

Python:
# Start
    if game_started == True:
        game_over = False
        t = pygame.time.get_ticks()
        clock.tick(fps)
        # Display instances
        screen.blit(bg, (0, 0))
        kivotos.draw()
        player.update()
        obstacle.update()
        draw_grid()
        
    if pause_btn.draw() == True:
        if resume_btn.draw() == True:
            print("resume")
        if restart_btn.draw() == True:
            print("restart")
        if main_menu_btn.draw() == True:
            print("main menu")
        game_started = not game_started
 
Joined
Dec 10, 2022
Messages
90
Reaction score
25
It looks like you're using pygame but, without knowing what all those functions are, it's kinda hard to help.
 
Joined
Jul 4, 2023
Messages
453
Reaction score
54
Did you try use like:

example of use as listed above:
Python:
import pygame as pg
import pygame.freetype as ft
import random

pg.init()
window = pg.display.set_mode((700, 500))
window_w, window_h = window.get_size()

pg.mouse.set_visible(True)
fps_clock = pg.time.Clock()

WINDOW_MARGIN = 10
BUTTON_GAP = 5
buttons = []

x = WINDOW_MARGIN
y = WINDOW_MARGIN
pause_button = pg.Rect(x, y, 70, 26)
buttons.append(pause_button)

x = WINDOW_MARGIN + pause_button.width + BUTTON_GAP
y = WINDOW_MARGIN
restart_button = pg.Rect(x, y, 65, 26)
buttons.append(restart_button)

x = WINDOW_MARGIN + pause_button.width + BUTTON_GAP + restart_button.width + BUTTON_GAP
y = WINDOW_MARGIN
main_menu = pg.Rect(x, y, 90, 26)
buttons.append(main_menu)

def draw_pause_button():
    text, background_color, font_color = ("Pause", "green", "black") if not paused else ("Resume", "red", "white")
    draw_button(pause_button, text, background_color, font_color)

def draw_restart_button():
    draw_button(restart_button, "Restart", "black", "white")

def draw_main_menu():
    draw_button(main_menu, "Main menu", "black", "white")

def draw_button(button, text, background_color, font_color):
    pg.draw.rect(window, background_color, button, border_radius=3)
    font = ft.SysFont('Arial', 16)
    text_rect = font.get_rect(text)
    text_rect.center = button.center
    font.render_to(window, text_rect.topleft, text, font_color)

def draw_text(text):
    # Displaying text in the center of the window
    font = ft.SysFont('Arial', 74)
    text_rect = font.get_rect(text)
    text_rect.center = (window_w // 2, window_h // 2)
    font.render_to(window, text_rect.topleft, text, "black")


text_to_display = None

game_started = False
game_over    = False
paused       = False


running = True
while running:
    window.fill("orange")
    draw_pause_button()
    
    keys = pg.key.get_pressed()   
    for event in pg.event.get():
        if event.type == pg.QUIT or keys[pg.K_ESCAPE]:
            running = False
        
        if event.type == pg.MOUSEBUTTONDOWN:
            if pause_button.collidepoint(event.pos):
                paused = not paused
                text_to_display = "PAUSED"

            if restart_button.collidepoint(event.pos):
                text_to_display = "RESTART"

            if main_menu.collidepoint(event.pos):
                text_to_display = "MAIN MENU"

    for button in buttons:
        if button.collidepoint(pg.mouse.get_pos()):
            pg.mouse.set_cursor(pg.SYSTEM_CURSOR_HAND)
            break
        else:
            pg.mouse.set_cursor(pg.SYSTEM_CURSOR_ARROW)

    if paused:
        draw_restart_button()
        draw_main_menu()
        
        draw_text(text_to_display)

    if not paused:
        if game_started == True:
            game_over = False           
            # Display instances
            #screen.blit(bg, (0, 0))
            #kivotos.draw()
            #player.update()
            #obstacle.update()
            #draw_grid()

        # pretend action
        draw_text("".join(random.choices(["0", "1"], k=10)))

    pg.display.flip()
    fps_clock.tick(45)
    
pg.quit()
 
Joined
Dec 10, 2022
Messages
90
Reaction score
25
I took a little different approach. I didn't change the pointer as I have found that it glitches a lot.
I create a button class and used sprite groups. Button 3 doesn't really do anything. Button 2 will display a pink box.
Then button 1 will pause and resume. While paused the other two buttons will display.

mybutton.py
Python:
import pygame

button_sprite = pygame.sprite.Group()

class Button(pygame.sprite.Sprite):
    def __init__(self, default_text='Button'):
        pygame.sprite.Sprite.__init__(self)
        # Defaults
        self.default_text = default_text
        self.text_color = 'white'
        self.text_hover_color = 'white'
        self.bg_color = 'blue'
        self.hover_color = 'skyblue'
        self.x = 0
        self.y = 0
        self.func = None
        self.type = None
                
        # Create and render button text
        self.font = pygame.font.SysFont(None, 24)
        self.text = self.font.render(self.default_text, True, self.text_color)

        # Get size of text
        self.text_width, self.text_height = self.font.size(self.default_text)
        
        self.button_size = (150, 40)
        self.image = pygame.Surface(self.button_size)
        self.image.fill(self.bg_color)
        self.rect = self.image.get_rect()

        # Center text on surface
        self.text_x = self.rect.width/2 - self.text_width/2
        self.text_y = self.rect.height/2 - self.text_height/2

        # Blit text to surface
        self.image.blit(self.text, (self.text_x, self.text_y))

        # Add button to sprite group
        button_sprite.add(self)

    def hover(self):
        ''' Method for hover effects '''
        self.font = pygame.font.SysFont(None, 24)
        self.text = self.font.render(self.default_text, True, self.text_hover_color)

    def reset(self):
        ''' Method for resetting hover effects '''
        self.font = pygame.font.SysFont(None, 24)
        self.text = self.font.render(self.default_text, True, self.text_color)
        
    def update(self):

        # Update button position
        self.rect.y = self.y
        self.rect.x = self.x

        # Get mouse position
        pointer = pygame.mouse.get_pos()
        
        # Detect if pointer collides with a button
        # and call appropiate function
        if self.rect.collidepoint(pointer):
            self.image.fill(self.hover_color)
            self.hover() 
        else:
            self.image.fill(self.bg_color)
            self.reset()

        # Blit text to button
        self.image.blit(self.text, (self.text_x, self.text_y))

game.py
Python:
import pygame
from mybutton import Button, button_sprite
from random import choices
from string import ascii_letters, digits

pygame.init()
pygame.font.init()

clock = pygame.time.Clock()
FPS = 10

window = (1280, 780)
screen = pygame.display.set_mode(window)



# Create functions for buttons
def func1():
    paused = False
    btn2 = Button('Button 2')
    btn2.x = 315
    btn2.y = 20
    btn2.func = func2
    btn2.type = 'square'

    btn3 = Button('Button 3')
    btn3.x = 520
    btn3.y = 20
    btn3.bg_color = 'brown'
    btn3.hover_color = 'orange'
    btn3.text_hover_color = 'brown'
    btn3.func = func3
        
def func2():
    square = pygame.Surface((100,100))
    square.fill('pink')
    screen.blit(square, (120,200))

def func3():
    print('Function 3')


'''
    Create some buttons
    button attributes:
        default_text
        text_color
        text_hover_color
        bg_color
        hover_color
        x
        y
        func
        type
'''
btn1 = Button('Pause')
btn1.x = 100
btn1.y = 20
btn1.bg_color = 'orangered'
btn1.text_color = 'black'
btn1.hover_color = 'red'
btn1.func = func1
btn1.type = 'resume'

pause = False
show_square = False
running = True
while running:
    pointer = pygame.mouse.get_pos()
    screen.fill(pygame.Color(180,180,180))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # This needs to be here so the function only fires once per click
        # Loop through sprites and detect collision
        for btn in button_sprite:
            if btn.rect.collidepoint(pointer):
                # If left mouse button pressed and type is resume/pause         
                if pygame.mouse.get_pressed()[0] and btn.type == 'resume':
                    # Button pressed set pause to True, change button text and call function
                    if not pause and btn.type == 'resume':
                        pause = True
                        btn.default_text = 'Resume'
                        btn.func()
                    else:
                        # Set pause to False and remove other buttons
                        pause = False
                        btn.default_text = 'Pause'
                        for sprite in button_sprite:
                            if sprite.type != 'resume':
                                sprite.kill()

                # Button 2 was pressed set show_square to True
                if pygame.mouse.get_pressed()[0] and btn.type == 'square':
                    show_square = True
                    

    # The game is running
    if not pause:
        letters = choices(ascii_letters+digits, k=20)
        color = 'limegreen'
        show_square = False

    # The game is paused
    else:
        letters = 'The game is paused'
        color = 'cyan'
    # Function call will draw a pink square
    if show_square:
        func2()


    # The text box and text
    font = pygame.font.SysFont(None, 45)
    text = font.render(''.join(letters), True, color)
    text_width, text_height = font.size(str(text))

    box = pygame.Surface((500, 40))
    box.fill('#444444')
    box_rect = box.get_rect()

    text_x = box_rect.width/2 - text_width/2
    text_y = box_rect.height/2 - text_height/2
    box.blit(text, (text_x, text_y))

    screen_rect = screen.get_rect()
    pos_x = screen_rect.width/2 - box_rect.width/2
    pos_y = screen_rect.height - 400

    screen.blit(box, (pos_x, pos_y))

    
    
    button_sprite.update()
    button_sprite.draw(screen)

    pygame.display.update()
    clock.tick(FPS)
 
Joined
Dec 10, 2022
Messages
90
Reaction score
25
I figured out how to keep the pointer from flickering. I set a cursor flag in the class and set it to either true or false
depending on if it collided with the button sprite. Here is the updated code with comments.
Note: I did not add any functionality to the buttons.

Python:
import pygame

pygame.init()

screen_size = (1280, 780)
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption('My PyGame Window')

allsprites = pygame.sprite.Group()
btn_sprites = pygame.sprite.Group()

running = True

class Button(pygame.sprite.Sprite):
    def __init__(self, btn_text='Button'):
        pygame.sprite.Sprite.__init__(self)
        self.x = 0
        self.y = 0
        self.bgcolor = 'blue'
        self.fgcolor = 'white'
        self.bghovercolor = 'skyblue'
        self.fghovercolor = 'black'
        self.btn_text = btn_text
        self.type = None
        self.function = None
        self.cursor = False

        self.font = pygame.font.SysFont(None, 30)
        self.text = self.font.render(self.btn_text, True, self.fgcolor)

        self.text_width, self.text_height = self.font.size(self.btn_text)

        self.image = pygame.Surface((self.text_width*2, self.text_height*2))
        self.image.fill(self.bgcolor)
       
        self.rect = self.image.get_rect()

        btn_sprites.add(self)
        allsprites.add(self)

    def update(self):
        # Set button position
        self.rect.x = self.x
        self.rect.y = self.y
        self.center = (self.rect.width/2 - self.text_width/2,
                        self.rect.height/2 - self.text_height/2)

        # Get pointer position
        pointer = pygame.mouse.get_pos()

        # Detect if pointer collides with button sprite
        if self.rect.collidepoint(pointer):
            self.image.fill(self.bghovercolor)
            self.text = self.font.render(self.btn_text, True, self.fghovercolor)
        else:
            self.image.fill(self.bgcolor)
            self.text = self.font.render(self.btn_text, True, self.fgcolor)
       
        # Blit text to button surface
        self.image.blit(self.text, self.center)


# Create some buttons
button1 = Button()
button1.bgcolor = 'orange'
button1.bghovercolor = 'red'
button1.fgcolor = 'white'
button1.fghovercolor = 'white'
button1.x = 50
button1.y = 20
button1.function = lambda: print('Button')

button2 = Button('Button 2')
button2.bgcolor = 'purple'
button2.bghovercolor = pygame.Color(180,90,220)
button2.fghovercolor = 'aqua'
button2.x = 220
button2.y = 20
button2.function = lambda: print('Button 2')

button3 = Button('Another Button')
button3.x = 420
button3.y = 20

while running:
    # Get pointer position
    pointer = pygame.mouse.get_pos()

    # Screen background color
    screen.fill('#ffffff')

    # Track events
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # Loop through button sprites and check if pointer/cursor has collided
        for button in btn_sprites:
            if button.rect.collidepoint(pointer):

                # Pointer has collided with the button
                button.cursor = True

                # Check if button has a function and execute
                # when left mouse button is pressed          
                if pygame.mouse.get_pressed()[0] and button.function != None:
                    button.function()
            else:
                # We are not over a button change pointer flag to False
                # and reset cursor to arrow
                button.cursor = False
                pygame.mouse.set_cursor()

    # Loop through button sprites and check pointer/cursor flag for True
    # If True change cursor to hand
    for btn in btn_sprites:
        if btn.cursor:
            pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_HAND)

    # Update and draw all sprites to screen
    allsprites.update()
    allsprites.draw(screen)
   
    pygame.display.update()
 
Joined
Dec 10, 2022
Messages
90
Reaction score
25
I tweaked the buttons a little more. I only have them to display some text. Could be used for any functions.

btn_class.py
Python:
import pygame

# Inialize pygame font
pygame.font.init()

# Create a sprite group
btn_sprites = pygame.sprite.Group()

class Button(pygame.sprite.Sprite):
    def __init__(self, x=0, y=0, text='Button'):
        pygame.sprite.Sprite.__init__(self)

        # Set Button Attributes
        self.border_color = '#999999'
        self.bgcolor = 'blue'
        self.fgcolor = 'white'
        self.bg_hover_color = 'mediumblue'
        self.fg_hover_color = 'cyan'
        self.text = text
        self.x = x
        self.y = y
        self.type = None
        self.function = None

        # These two lines should not be changed
        self.pointer = pygame.mouse.get_pos()
        self.cursor = False
        
        # Setup the font and button text
        self.font = pygame.font.SysFont(None, 35)
        self.btn_text = self.font.render(self.text, True, self.fgcolor)

        # Get text width and height
        self.text_width, self.text_height = self.font.size(str(self.text))

        # Create the button surface
        self.button = pygame.Surface((self.text_width*2, self.text_height*2))
        self.button.fill(self.bgcolor)

        # Get button size
        self.button_rect = self.button.get_rect()

        # Get the center to place button text
        self.center_text = (
            self.button_rect.width/2 - self.text_width/2,
            self.button_rect.height/2 - self.text_height/2
        )

        # Blit text to button
        self.button.blit(self.btn_text, self.center_text)

        # Create the shadow image
        self.image = pygame.Surface((self.button_rect.width+5, self.button_rect.height+5)).convert()
        self.image.fill(self.border_color)
        self.rect = self.image.get_rect()
        self.image.set_alpha(200)

        # Get the center for button and shadow
        self.center_button = (
            self.rect.width/2 - self.button_rect.width/2,
            self.rect.height/2 - self.button_rect.height/2
        )

        # Add Button to sprite group
        btn_sprites.add(self)
        

    def update(self):
        ''' Method for updating button effects '''

        # Place the button
        self.rect.x = self.x
        self.rect.y = self.y

        # Get the pointer position
        self.pointer = pygame.mouse.get_pos()

        # If the pointer hovers over a button make highlight effect
        if self.rect.collidepoint(self.pointer):
            self.image.set_alpha(220)
            self.button.fill(self.bg_hover_color)

            # Effects for mouse click
            if pygame.mouse.get_pressed()[0] and self.function != None:
                self.image.set_colorkey(self.border_color)
                self.image.set_alpha(255)
            else:
                # Reset shadow
                self.image.set_colorkey()
        else:
            # Reset the button to default
            self.image.set_alpha(200)
            self.button.fill(self.bgcolor)

        # Update the button
        self.button.blit(self.btn_text, self.center_text)
        self.image.blit(self.button, self.center_button)

buttons.py
Python:
import pygame
from btn_class import Button, btn_sprites

# Setup pygame window
window_size = (1280, 780)
window = pygame.display.set_mode(window_size)

# Pygame caption
pygame.display.set_caption('My PyGame Window')

# Setup clock
clock = pygame.time.Clock()
fps = 60

# Window color
window_color = '#ffffff'

# Some flags
running = True
cursor = False
text = ''

# Create a sprite group
# This group is for displaying buttons only
allsprites = pygame.sprite.Group()

# Create some buttons
'''
    Button attributes with defaults:
        border_color = '#999999'
        bgcolor = 'blue'
        fgcolor = 'white'
        bg_hover_color = 'mediumblue'
        fg_hover_color = 'cyan'
        text = text
        x = x
        y = y
        type = None
        function = None
'''

def draw_text(text=None):
    '''
        Function will draw text to window
    '''
    font = pygame.font.SysFont(None, 40)
    string = font.render(text, True, 'black')
    string_width, string_height = font.size(str(text))
    window_width, window_height = window.get_rect().width, window.get_rect().height
    
    center = (
        window_width/2 - string_width/2,
        window_height/2 - string_height/2
    )
    
    window.blit(string, center)


btn1 = Button()
btn1.x = 20
btn1.y = 20
btn1.function = lambda: draw_text(f'You clicked {btn1.text.capitalize()}')

btn2 = Button(text='Button 2')
btn2.x = 220
btn2.y = 20
btn2.bgcolor = 'orange'
btn2.bg_hover_color = 'orangered'
btn2.function = lambda: draw_text(f'You clicked {btn2.text.capitalize()}')

btn3 = Button(text='Clear')
btn3.x = 460
btn3.y = 20
btn3.bgcolor = 'tomato'
btn3.bg_hover_color = 'red'
btn3.function = ''
btn3.type = 'clear'

# Add buttons to allsprites group
allsprites.add(btn1, btn2, btn3)

while running:
    window.fill(window_color)

    # Track pygame events
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # loop through btn_sprite group
        for button in btn_sprites:

            # Check for collisions/hover
            if button.rect.collidepoint(button.pointer):

                # We are over a button change pointer to hand
                button.cursor = True

                # Check if mouse button is clicked and we have a function to fire
                # Can add a type here to check for a specific button
                if pygame.mouse.get_pressed()[0] and button.function != None:
                    if button.type == 'clear':
                        text = ''
                    else:
                        text = f'You pressed {button.text}'                 
            else:
                # We are not over a button return pointer to default
                button.cursor = False
                pygame.mouse.set_cursor()

    # Loop through buttons and if flag is True change pointer to hand
    for button in btn_sprites:
        if button.cursor:
            pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_HAND)

    # Update allsprites and draw to window
    allsprites.update()
    allsprites.draw(window)

    draw_text(text)

    pygame.display.update()
    clock.tick(fps)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,879
Messages
2,569,939
Members
46,232
Latest member
DeniseMcVi

Latest Threads

Top