Okay so I'm writing a code for a game and the way its currently programmed is the main menu is contained within a large function that references another function, and so on. Not too complicated. But (as you'll see with the code below) I have all the essential variables set before the functions even happen, at the very beginning of the code.

import pygame, sys, time, math

##This is where the variables are set
pygame.init()
DISPLAY = pygame.display.set_mode((1023, 647))
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
clock = pygame.time.Clock()
active = True
started = False
mainScreen = True
coordsX = 0
coordsY = 0
coordsZ = 0
coordsW = 0

def backMain(fps):
    ##Loads main menu
    mainscreendisplayimg = pygame.image.load('mainScreen.png')
    def mainscreen(x, y):
        DISPLAY.blit(mainscreendisplayimg, (x, y))
    mainscreen(1, 1)

    while active:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_p:
                    if started == False:
                        if mainScreen == True:
                            started = True
                            mainScreen = False

        if started == True:
            forwardMain(15)
            started = False
        pygame.display.update()
        clock.tick(fps)

def ultCoords():
    def c0_0_0_0():
        pygame.draw.rect(DISPLAY, GREEN, (507, 333, 8, 8), 0)

def forwardMain(fps):
    ultCoords()
    c0_0_0_0()

backmain(15)

This should display a rectangle on the screen and so on so forth, but instead it gives me an error saying that the variable 'started' is referenced before assignment

This means (I think) that the variable is being used before it's assigned, but it's clearly assigned up at the top, well before any of the functions use it.

Any help is appreciated, thank you!

Dani AI

Generated

Quick diagnosis and a few practical fixes. — the error comes from Python treating any name that is assigned anywhere inside a function as a local name for the whole function. That means your if started == False: is trying to read a local started before it has been set, producing an UnboundLocalError. already showed the classic global vs. object approaches; below are a couple of safe, easy alternatives plus two additional issues visible in your snippet.

A small change that avoids rebinding the name is to keep all flags in a single mutable state container (a dict). Mutating the container does not make the name local:

state = {'started': False, 'mainScreen': True}

def backMain(fps):
    if not state['started'] and state['mainScreen']:
        state['started'] = True
        state['mainScreen'] = False
    # continue using state[...] inside your loop

A more testable, functional pattern is to have menu functions accept and return state instead of touching globals:

def back_main(fps, state):
    state = dict(state)
    if not state['started'] and state['mainScreen']:
        state['started'] = True
        state['mainScreen'] = False
    return state

state = back_main(15, state)

If you prefer nested functions, Python 3 supports nonlocal so an inner function can assign a name in its enclosing scope. Also note two other bugs in the snippet: c0_0_0_0() is defined inside ultCoords() but then called from elsewhere (won’t be visible unless returned or called inside ultCoords), and Python is case-sensitive — backmain(15) won’t match backMain. Use quick prints, logging, or pdb to inspect scope, and for any non-trivial game prefer a small Game object to hold state (cleaner as the project grows).

The problem is that when a variable appears on the left hand side of the = operator in a function, such as in

def foo():
    started = "fubar"

then the rule is that this variable is a local variable in function foo. It means that if there is another variable in the global namespace, such as

started = False

then these are two different variables, and setting started in foo() has no effect on the global variable started.

There are two main workarounds for this. The first one is a quick and dirty fix: you can add a globaldeclaration at the very beginning of function foo()

def foo():
    global started
    started = "fubar"

This works, but it is not good python programming because with more than one variable, it creates obfuscated code. You'll notice that serious python code almost never uses the global statement.

The second workaround is to use object attributes instead of global variables. The code could be written

class Game(object):
    def __init__(self):
        self.started = False

    def foo(self):
        self.started = "fubar"

if __name__ == '__main__':
    game = Game()
    game.foo()

This is by far the preferred way to handle this issue.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.