1

Why do I get a NameError exception in this program?

I am programming a Python plane fight game using pygame. I have just finished added the plane PNG to the background. However, when I want to test the movement of the plane, the error is raised and I couldn't find why it occurred.

Error traceback:

Traceback (most recent call last):
  File "C:\Users\Desktop\Plane Fight\Plane Fight.py", line 34, in <module>
    main()
  File "C:\Users\Desktop\Plane Fight\Plane Fight.py", line 29, in main
    draw_window()
  File "C:\Users\Desktop\Plane Fight\Plane Fight.py", line 12, in draw_window
    win.blit(leftjet, (left.x, left.y))
NameError: name 'left' is not defined

Code:

import pygame
import os

win = pygame.display.set_mode((900, 500)) #生成一个900*500分辨率的游戏界面
pygame.display.set_caption("Plane Fight Game")

leftjet = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.join('fighterjet.jpg')), (55 ,40)), 270)
rightjet = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.join('fighterjet.jpg')), (55 ,40)), 90)

def draw_window():
    win.fill((0, 0, 0)) #设置背景为黑色
    win.blit(leftjet, (left.x, left.y))
    win.blit(rightjet, (right.x, right.y))
    pygame.display.update()

def main():
    left = pygame.Rect(100, 100, 55, 40)
    right = pygame.Rect(800, 100, 55, 40)
    
    run = True
    while run:
        pygame.time.Clock().tick(60) #设置游戏帧率为60帧

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False

        right.x += 1
        draw_window()
        
    pygame.quit()

if __name__ == "__main__":
    main()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174

3 Answers3

2

You accessed local variables (left, right) in main().

edit to following code.

import pygame
import os

win = pygame.display.set_mode((900, 500)) #生成一个900*500分辨率的游戏界面
pygame.display.set_caption("Plane Fight Game")

leftjet = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.join('fighterjet.jpg')), (55 ,40)), 270)
rightjet = pygame.transform.rotate(pygame.transform.scale(pygame.image.load(os.path.join('fighterjet.jpg')), (55 ,40)), 90)

def draw_window(left, right):
    win.fill((0, 0, 0)) #设置背景为黑色
    win.blit(leftjet, (left.x, left.y))
    win.blit(rightjet, (right.x, right.y))
    pygame.display.update()

def main():
    left = pygame.Rect(100, 100, 55, 40)
    right = pygame.Rect(800, 100, 55, 40)
    
    run = True
    while run:
        pygame.time.Clock().tick(60) #设置游戏帧率为60帧

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False

        right.x += 1
        draw_window(left, right)
        
    pygame.quit()

if __name__ == "__main__":
    main()
Jacob Lee
  • 4,405
  • 2
  • 16
  • 37
0

The pygame.Rect objects left and right are local variables of main(). In other words, they are variables which belong to the local scope of main(). Since this is the case, left and right can only be referenced inside of the main() function. Thus, left and right are undefined in draw_window().

The easiest solution, in this case, would be to add the parameters left and right to the function draw_window(). Then, when calling draw_window() in main(), pass the variables left and right.

def draw_window(left, right):    # Require 'left' and 'right' as parameters
    win.fill((0, 0, 0))
    win.blit(leftjet, (left.x, left.y))
    win.blit(rightjet, (right.x, right.y))
    pygame.display.update()

def main():
    left = pygame.Rect(100, 100, 55, 40)
    right = pygame.Rect(800, 100, 55, 40)
    
    run = True
    while run:
        pygame.time.Clock().tick(60)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False

        right.x += 1
        draw_window(left, right)    # Pass 'left' and 'right'
        
    pygame.quit()

See the Python Programming FAQ for a summary on local and global variables.

Note: Alternatively, you could have defined left and right in the global scope and accessed the variables within draw_window() and main() using the global keyword (when necessary). While it is a solution, it is not recommended, as it infringes on readability, and somewhat defeats the purpose of a function: to create a 'self-contained' block of code.

Jacob Lee
  • 4,405
  • 2
  • 16
  • 37
0

Look at the example I have provided below.

def respond():
    left += 90
    right += 50
def call():
    left = 0 
    right = 0 
    respond()
call()

This is basically the structure of your code. What is going wrong is, variables left & right belong to the function call(), they cannot be used outside of the function. So in respond we break that rule, and get the error left is not defined. So in order to solve this problem, we make left&right accessible to respond by passing them in as arguments.

def respond(left,right):
    left += 90
    right += 50
def call():
    left = 0 
    right = 0 
    respond(left,right)
call()

no error occurs.

Buddy Bob
  • 5,829
  • 1
  • 13
  • 44