-1

I am making a program with a start and help menu, as well as other functions. The buttons on the "main menu" work perfectly, but once I enter the Help menu, the buttons I have programmed for screen navigation do not work properly. Please feel free to look at the code below. I keep getting an error that says "BackHelpRect not defined". BackHelpRect is a rectangle I have drawn around my image buttons (as for all the rest of my buttons) to sense for when the mouse is touching them. It works for the main menu buttons but once I go into the help menu, the rectangles for those buttons "disappear". If you have a solution, please respond, it would be greatly appreciated. :)

Sorry I have attached my entire code, but everything is called within other functions and it all works in sync with each other. Sorry if it is very long.

import pygame
import time
import smtplib
import webbrowser
pygame.init() # Starts pygame.
white = (255, 255, 255)
blue = (0, 100, 175)
black = (0, 0, 0)# Initialising Python with colours and a window size.
Event = []
AllTasks = []
MenuStatus = ""
def OpenMainMenu(): # To open Main Menu.
    MenuStatus = "Main Menu" # In case the code needs to know what menu is currently projected.
    pygame.display.set_caption("Main Menu") # Naming the New Window.
    CurrentMenu = pygame.image.load(r'D:\Holiday Planner Screen Resources\Main Menu.jpg') # Opening a custom made Screen.
    Screen.blit(CurrentMenu, (0, 0))
    CreateEventB()
    OpenEventB()
    HelpB()
    pygame.display.update()# Loads the Main Menu Screen.
    ButtonInteract()
def CreateEventB(): # To Open the "Create Menu Button".
    CreateButton = pygame.image.load(r'D:\Holiday Planner Screen Resources\Create Event.jpg') # Open the custom button design.
    CreateButton = pygame.transform.scale(CreateButton, (174, 85))
    global CreateRect
    CreateRect = Screen.blit(CreateButton, (425, 325))
    pygame.display.update(CreateRect)
def OpenEventB(): # To Open the "Create Menu Button".
    OpenButton = pygame.image.load(r'D:\Holiday Planner Screen Resources\Open Event.jpg') # Open the custom button design.
    OpenButton = pygame.transform.scale(OpenButton, (179, 85))
    global OpenRect
    OpenRect = Screen.blit(OpenButton, (225, 325))
    pygame.display.update(OpenRect)
def HelpB():
    HelpButton = pygame.image.load(r'D:\Holiday Planner Screen Resources\Help Button.jpg') # Open the custom button design.
    HelpButton = pygame.transform.scale(HelpButton, (151, 51))
    global HelpRect
    HelpRect = Screen.blit(HelpButton, (335, 415))
   pygame.display.update(HelpRect)
def BackHelp():
    BackHelpB = pygame.image.load(r'D:\Holiday Planner Screen Resources\BackHelp.jpg') # Open the custom button design.
    BackHelpB = pygame.transform.scale(BackHelpB, (235, 84))
    global BackHelpRect
    BackHelpRect = Screen.blit(BackHelpB, (45, 490))
    pygame.display.update(BackHelpRect)
def NextHelp():
    NextHelpB = pygame.image.load(r'D:\Holiday Planner Screen Resources\NextHelp.jpg') # Open the custom button design.
    NextHelpB = pygame.transform.scale(NextHelpB, (233, 85))
    global NextHelpRect
    NextHelpRect = Screen.blit(NextHelpB, (545, 490))
    pygame.display.update(NextHelpRect)
def FinishHelp():
    FinishHelpB = pygame.image.load(r'D:\Holiday Planner Screen Resources\FinishHelp.jpg') # Open the custom button design.
    FinishHelpB = pygame.transform.scale(NextHelpB, (230, 85))
    global FinishHelpRect
    FinishHelpRect = Screen.blit(FinishHelpRect, (545, 490))
    pygame.display.update(FinishHelpRect)  
def ButtonInteract(): # A function that helps to connect button interactions to their respective functions.
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                if CreateRect.collidepoint(event.pos):
                    CreateEvent()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if OpenRect.collidepoint(event.pos):
                    Event, AllTasks = OpenEvent("BerlinTestTrip")
                    print(Event, AllTasks)
            if event.type == pygame.MOUSEBUTTONDOWN:
                if HelpRect.collidepoint(event.pos):
                     MenuStatus = "Help menu 1"
                     Help()
def ButtonsForHelp(): # A seperate button interaction pathway for help buttons as they are housed on a different screen.
    global BackHelpRect
    global NextHelpRect
    global FinishHelpRect
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.MOUSEBUTTONDOWN:
                if BackHelpRect.collidepoint(event.pos): # Button navigaton.
                    if MenuStatus == "Help menu 1":
                        OpenMainMenu()
                    if MenuStatus == "Help menu 2":
                        MenuStatus = "Help menu 1"
                        Help()
                    if MenuStatus == "Help menu 3":
                        MenuStatus = "Help menu 2"
                        Help()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if NextHelpRect.collidepoint(event.pos): # Button navigaton.
                    if MenuStatus == "Help menu 1":
                        MenuStatus = "Help menu 2"
                        Help()
                    if MenuStatus == "Help menu 2":
                        MenuStatus = "Help menu 3"
                        Help()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if FinishHelpRect.collidepoint(event.pos): # Button navigaton.
                    if MenuStatus == "Help menu 3":
                        OpenMainMenu()

def CreateEvent():
    print ("Created")

def OpenEvent(EventSaveName):
    print ("Opened")
def Help():
    pygame.display.set_caption("Help Menu") # Naming the New Window.
    CurrentMenu = pygame.image.load(r'D:\Holiday Planner Screen Resources\Help Menu 1.jpg') # Opening a custom made Screen.
    Screen.blit(CurrentMenu, (0, 0))
    pygame.display.update()
    if MenuStatus == "Help menu 1":
        CurrentMenu = pygame.image.load(r'D:\Holiday Planner Screen Resources\Help Menu 1.jpg') # Opening a custom made Screen.
        Screen.blit(CurrentMenu, (0, 0))
        pygame.display.update()# Loads the menu Screen.
        BackHelp()
        NextHelp()
    if MenuStatus == "Help menu 2":
        CurrentMenu = pygame.image.load(r'D:\Holiday Planner Screen Resources\Help Menu 2.jpg') # Opening a custom made Screen.
        Screen.blit(CurrentMenu, (0, 0))
        pygame.display.update()# Loads the menu Screen.
        BackHelp()
        NextHelp()
    if MenuStatus == "Help menu 3":
        CurrentMenu = pygame.image.load(r'D:\Holiday Planner Screen Resources\Help Menu 3.jpg') # Opening a custom made Screen.
        Screen.blit(CurrentMenu, (0, 0))
        pygame.display.update()# Loads the menu Screen.
        BackHelp()
        FinishHelp()
    ButtonsForHelp()

# MAIN BODY

Screen = pygame.display.set_mode((824, 620))

OpenMainMenu()
pygame.display.update()

Thanks.

JayRoy
  • 105
  • 6
  • I don't know how to help you, your code is really, really hard to read. I strongly recommend you read up on how to write prettier code [tip](https://gameprogrammingpatterns.com/), which will allow you to solve your problem yourself. – Nearoo Feb 04 '20 at 16:37

1 Answers1

0

The issue is that the main loop is referencing BackHelpRect before it is defined. It's easy to replicate this, just select the "back" menu options on the first screen. To debug this I added a print( "BackHelp Defined HERE" ) to the BackHelp() function. It's not always called beforehand.

To fix this, perhaps your code can define all these Images and Rects at once before the menu processing begins. Something like:

def preloadButtons():
    global HelpButton, HelpButtonRect
    global BackHelpButton, BackHelpRect
    # etc. etc.

    HelpButton     = pygame.image.load('button.jpg') # Open the custom button design.
    HelpButton     = pygame.transform.scale(HelpButton, (151, 51))
    HelpButtonRect = HelpButton.get_rect()
    HelpButtonRect.topleft = (335, 415)

    BackHelpButton     = pygame.image.load('button.jpg') # Open the custom button design.
    BackHelpButton     = pygame.transform.scale(BackHelpButton, (235, 84))
    BackHelpButtonRect = BackHelpButton.get_rect()
    BackHelpButtonRect.topleft = (45, 490)

Storing all these buttons as separate globals is not a very good design, and it's already causing complexity in the drawing and event-testing throughout the rest of the program. It would be better to pack all the attributes (image, size, position, rect) of a button into a data structure. It's doesn't have to be a Python class, just putting each buttons properties into a list would be a step-forward, and then maybe all those lists into a single all_buttons list.

For example, here we define a list of button properties, and then iterate through these to crate a simpler list of button name/image/rect.

help_button      = [ 'help', 'help_button.jpg', (151, 51), (335, 415) ]
back_help_button = [ 'back', 'back_button.jpg', (235, 84), ( 45, 490) ]
# ... TODO: rest of buttons
all_buttons_properties = [ help_button, back_help_button ]

# Initialise buttons
all_buttons = []
for butt in all_button_properties:
    button_image = pygame.image.load( butt[1] )                     # load
    button_image = pygame.transform.scale( button_image, butt[2] )  # resize
    button_rect  = button_image.get_rect()
    button_rect.topleft = butt[3]                                   # move
    all_buttons.append( butt[0], button_image, button_rect )

This gives you a simple all_buttons list of lists [ button-name, resized-button-image, pre-positioned-button-rect ].

And probably you want if ... elif ... for these buttons tests, not if ... if ...:

        if event.type == pygame.MOUSEBUTTONDOWN:
            if NextHelpRect.collidepoint(event.pos): # Button navigaton.
                if MenuStatus == "Help menu 1":
                    MenuStatus = "Help menu 2"
                    Help()
                if MenuStatus == "Help menu 2":
                    MenuStatus = "Help menu 3"
                    Help()

What happens when MenuStatus equals "Help menu 1" -> it becomes "Help menu 2", but then the very next if changes this again to "Help menu 3"

Kingsley
  • 14,398
  • 5
  • 31
  • 53
  • Thanks for your reponse @Kingsley, it has helped clear up the definition problem but a new error says that: BackHelp.topleft = (45, 490), TypeError: 'tuple' object is not callable. Anyway to fix this? – JayRoy Feb 06 '20 at 09:30
  • @JayRoy - "TypeError: 'tuple' object is not callable" means that the code has assigned some variable to a tuple, e.g.: `x = (1, 2, 3)`, but is then trying to use `x` as if it's a function: `x( 3.141 )`. – Kingsley Feb 06 '20 at 21:27
  • Oh okay thanks! This comes up the .topleft bit of each rectangle. Do you how I could fix this? – JayRoy Feb 07 '20 at 10:07
  • @jayroy - The most must have something like `x.topleft()`, remove the brackets. – Kingsley Feb 10 '20 at 21:14
  • Thanks a lot @Kingsley , this helped! – JayRoy Feb 11 '20 at 14:13