Search code examples
pythonpygamewindowrectpython-3.6

Pygame rect button stuck on screen, and close window code not working


I'm currently programming a game in Python 3.6 using Pygame. My game has a start menu, with a button that is highlighted when hovered over. When the button is clicked, the start menu disappears and the game starts. The only problem is, the start button remains... I've tried using boolean values and if statements to make it disappear when the menu does, but to no avail.

To make matters worse, the pygame code that allows the window to be closed doesn't work (highlighted by commenting out). Could anyone help me with these small problems? They seem trivial, but I'm new to pygame and I can't seem to find a fix anywhere.

You will need the pictures below to run the program:

This is the photo of the girl.

This is the background photo.

The code:

#Imports
import sys
import pygame
pygame.init() #Initialise Pygame

#RGB colours
GREY = (128,128,128)
WHITE = (255,255,255)
BLACK = (0,0,0)

#fonts
title_font = pygame.font.Font('freesansbold.ttf',72)
menu_font = pygame.font.Font('freesansbold.ttf',32)

#images
girl_img = pygame.image.load('emily.png')
background_img = pygame.image.load('tech_lab.png')

class Game: #Game Class

    def __init__(self): #Constructor
        self.size = width, height = (1000,563)
        self.screen = pygame.display.set_mode(self.size)

    def menu_screen(self): #Menu Screen Function
        intro = True
        while intro:
##            for event in pygame.event.get():  #To close window
##                print(event)
##                if event.type == pygame.QUIT:
##                    pygame.quit()
##                    sys.exit()

            self.screen.fill(GREY) #Set background colour
            self.screen.blit(title_font.render('EXAMPLE', True, BLACK), (330,100)) #Display game title
            start_button = pygame.draw.rect(self.screen, (BLACK), pygame.Rect(410,310,180,55)) #Display start button rect
            self.screen.blit(menu_font.render('Play', True, GREY), (425,310)) #Display start button text
            pygame.display.flip() #Update display

            while True:
                pygame.event.get() #Get pygame events
                click_pos = pygame.mouse.get_pos() #Get mouse position
                if 410+180 > click_pos[0] > 410 and 310+55 > click_pos[1] > 310: #If mouse position within start button rect...
                    pygame.draw.rect(self.screen, (WHITE), pygame.Rect(410,310,180,55)) #then change colour of start button rect
                    if (pygame.mouse.get_pressed())[0] == 1: #If start button rect clicked...
                        start_game(self) #Start main game
                else:
                    pygame.draw.rect(self.screen, (BLACK), pygame.Rect(410,310,180,55)) #Otherwise start button rect colour is black

                self.screen.blit(menu_font.render('Play', True, GREY), (425,310))#Display start button text 
                pygame.display.flip() #Update display

def start_game(game): #Main game function
    game.screen.blit(background_img, [0,0]) #Display background image
    game.screen.blit(girl_img, [80,25]) #Display image
    pygame.display.flip() #Update display

def main():
    game = Game() #Instantiate class 'game'
    game.menu_screen() #Call menu screen function

main()

Solution

  • This loop within a loop thing is going to cause nothing but problems and has to go:

    while intro:
        ....
        while True
        ....
    

    here is some pseudo code:

    Class Game:
        def menu_screen():
            displaying = True
            while displaying:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        sys.exit()
                    elif event.type == pygame.MOUSEBUTTONDOWN:
                        # evaluate mouse click
                        if clicked button
                            displaying = False
                            self.game()
                # drawing code for your images
                pygame.display.flip()
    
        def game():
            game_running = True
            while game_running:
                # game running logic and drawing
    
    def main():
        # get the Game setup and call main menu
    

    Basically, have your Game class control everything. it will have a menu function which displays the menu. Then they click the button and it goes to a different function within the game class for the actual game.

    The start button was remaining because you never cleared the screen when going into the start_game() function. As far as why the close window button wasn't working, it is because of the loop within a loop as i mentioned above. You were trapped in the inner

    while True:
    

    loop and you could never get back to the event checking from above. (The quit code itself is fine, although you don't need pygame.quit() because you are quitting the program entirely with sys.ext())

    Short of completely reworking your code, this can get you started on the right track.