Why I got NameError when I am using pygame? [duplicate] - python

This question already has answers here:
Using global variables in a function
(25 answers)
Closed 1 year ago.
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()

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()

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.

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.

Related

why is my class getting the wrong values?

I recently started exploring classes and I have made my first class (sort of) but it doesn't seem to be working. I have code creating the class and function, then takes the values and blits an image to certain coordinates. for some reason It takes the values from inside the class instead of what I told it to have. I am new to classes so I'm not sure what to do, please help, thanks!
import pygame
pygame.init()
Screen = pygame.display.set_mode((800, 400))
TC = pygame.image.load("TC.png").convert_alpha()
ANUM = 0
class MTC() :
def __init__(self,) :
self.Tx = 0
self.Ty = 0
Screen.blit(TC,(self.Tx,self.Ty))
TMTC = MTC()
TMTC.Tx = 800
TMTC.Ty = 800
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
pygame.display.update()
The image is blit in the constructor. At this point the coordinates are not yet changed. You have add a method that blits the object:
class MTC() :
def __init__(self,) :
self.Tx = 0
self.Ty = 0
def dra():
Screen.blit(TC,(self.Tx,self.Ty))
Call the draw method in the application loop:
TMTC = MTC()
TMTC.Tx = 800
TMTC.Ty = 800
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
Screen.fill((0, 0, 0))
TMTC.draw()
pygame.display.update()
You are calling Screen.blit in the class constructor which is executed when your class is instantiated (TMTC = MTC()).
You are then setting the tx and ty after Screen.blit has already run

Pygame class spawns rect and then it dissapears, how do I get it to stay?

So I'm trying to implement a class for a basic game. It woked without the class but now instead of spawning the "coin" it pops up and then immediatly dissapears. No idea as it's in the main loop. I have a moving "player" that works fine.
Here's my code:
class Coin_Class:
def __init__(self):
coin_1 = pygame.Rect(425, 30, 40, 40)
pygame.draw.rect(WIN, YELLOW, coin_1)
pygame.display.update()
# def coin_collect():
# if player.colliderect():
# coin_1.x = random.randint(0, 800)
# coin_1.y = random.randint(0, 250)
# pygame.event.post(pygame.event.Event(coin_collected))
# global score
# score += 1
# print(score)
coin_class = Coin_Class()
# main function loop
def main():
score_check = 0
clock = pygame.time.Clock()
run = True
while run:
# game speed
clock.tick(FPS)
# initialise pygame
pygame.init()
# checking all the events in pygame and looping them
for event in pygame.event.get():
# checking quit function is pressed
if event.type == pygame.QUIT:
run = False
pygame.quit()
exit()
keys_pressed = pygame.key.get_pressed() # recognise key presses
player_movement(keys_pressed, player) # movement function
draw_window() # create window function
coin_class
main()
# runs the main file
if __name__ == "__main__":
main()
Add a draw method to the coin class (also class names per PEP 8 should be in CapitalCase not Capital_Snake_Case so CoinClass):
class Coin_Class:
def __init__(self):
self.coin_1 = pygame.Rect(425, 30, 40, 40)
...
def draw(self):
pygame.draw.rect(WIN, YELLOW, self.coin_1)
And in the loop instead of using
coin_class
you would now use
coin_class.draw()
The rest can stay the same, except remove pygame.init() from the loop and put it somewhere at the start of the code after imports

Python: Function name not defined

Basically, I'm working on an AI project and I am trying to make a loop that does it as long as one coordinate is <= to another coordinate and I have defined a function but when I try to call it it has this error
Traceback (most recent call last):
File "not important", line 66, in
A()
NameError: name 'A' is not defined
and if I try to re-arrange the definition it runs into a variable problem fixed by being placed where it is.
Here is my code (Note I am using pygame for the actual Interface)
import pygame as pg
import math
import time
import random
#starts pygame/create window
pg.init()
screen = pg.display.set_mode((800,600))
pg.display.set_caption("AI ALG")
clock = pg.time.Clock()
#Presets
KillerX = 50
KillerY = 50
EnemyX = 375
EnemyY = 275
gray = (255,255,255)
font = pg.font.Font(None, 32)
TICKSPASSED = 0
font_color = (100, 200, 150)
killertexture = pg.Surface((25,25))
killertexture.fill((0, 255, 0))
enemytexture = pg.Surface((25,25))
enemytexture.fill((255, 0, 0))
startAI = False
#main loop
runing = True
while runing:
ticktxt = font.render(str(TICKSPASSED), True, font_color)
activetxt = font.render(str(startAI), True, font_color)
COO1 = font.render(str(KillerX), True, font_color)
clock.tick(60)
keys = pg.key.get_pressed()
#events
if keys[pg.K_SPACE]:
startAI = True
TICKSPASSED += 1
for event in pg.event.get():
#if event.type == pg.QUIT:
#runing = False
if event.type == pg.QUIT:
runing = False
#update
#render
screen.fill(gray)
screen.blit(ticktxt, ((8,8), (8,8)))
screen.blit(activetxt, ((730,8), (792,8)))
screen.blit(COO1, ((730,8), (792,8)))
screen.blit(killertexture, (KillerX,KillerY))
screen.blit(enemytexture, (EnemyX,EnemyY))
A()
pg.display.flip()
def A():
if not KillerX <= EnemyX:
KillerX =- .5
pg.quit()
Any help would be awesome, thanks
also sorry if my code is messy :)
You should define A before it is referenced. Move the definition of A before the while loop, in which A is called, and the error would go away.
Note that you should also either declare KillerX and EnemyX as global variables in the function A, or make them parameters to A and make A return the altered KillerX.
The code you're running is in-line, rather than in a function, so it is run as soon as it's encountered in the file, which is before it has seen the definition of function A. You can move the definition of A up to a point before it's referenced, or you can place your main code in a function that you call at the end of the file. The definition of A just needs to be seen before you attempt to call it.

python/pygame image cant be found the the same folder

hello im new to python/pygame and tried to make a basic project. it did not turn out as planned as i don't understand this error if you can tell my why my image is not loading it will very much appreciated. Traceback (most recent call last):
File "C:\Users\Nicolas\Desktop\template\templat.py", line 15, in <module>
screen.fill(background_colour)
NameError: name 'background_colour' is not defined
this is the error i was speaking of however i have fixed now. how ever now the screen opens displayes the background and crashes.
import pygame, sys
pygame.init()
def game():
background_colour = (255,255,255)
(width, height) = (800, 600)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Tutorial 1')
pygame.display.set_icon(pygame.image.load('baller.jpg'))
background=pygame.image.load('path.png')
target = pygame.image.load('Player.png')
targetpos =target.get_rect()
screen.blit(target,targetpos)
screen.blit(background,(0,0))
pygame.display.update()
while True:
screen.blit(background,(0,0))
screen.blit(target,targetpos)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if__name__==('__main__')
game()
You missed the __init__ definition!
While your code does run, it is not what you want. There's an infinite loop inside the definition of the class, which means, however you are running this, there's something missing. You should put this code (most of it at least) inside the __init__ function, and then create an instance of the class.
This is what I assume you want:
import pygame, sys
class game():
width, height = 600,400
def __init__(self):
ball_filename = "Ball.png"
path_filename = "path.png"
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption('Star catcher')
self.background = pygame.image.load(path_filename)
self.screen.blit(self.background,(0,0))
self.target = pygame.image.load(ball_filename)
def run(self):
while True:
self.screen.blit(self.background, (0,0))
targetpos = self.target.get_rect()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if __name__ == "__main__":
# To run this
pygame.init()
g = game()
g.run()
UPDATE:
I made more modifications than what you must do, but they could be useful. I did not test this, but it should be fine.
The error of width and height not being defined is because they are not local/global variables, but bound to the class and/or the instance of the class, therefore in their namespace. So you need to access these either via game.width (per class) or self.width (per instance, only inside a method defined in the class) or g.width (per instance, if you are outside the class definition and g is an instance of game class).
I hope I'm clear. :)

Using classes in Pygame

Okay, so I am starting to have fun with pygame. But I've got a problem. I tried to somehow enchance my code, make it organised, so I've decided to use classes here. It looks like this:
import pygame
from pygame.locals import *
import sys
pygame.init()
class MainWindow:
def __init__(self, width, height):
self.width=width
self.height=height
self.display=pygame.display.set_mode((self.width,self.height))
pygame.display.set_caption("Caption")
def background(self)
img = pygame.image.load("image.png")
self.display.blit(img, (0,0))
mainWindow = MainWindow(800,600)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.exit()
sys.exit()
mainWindow.background()
pygame.display.update()
Okay, works. But what if I want to, for example fill the windows with white color? Then I have to define a method fill(), which will just self.display.fill(), right? Is there a way, to handle it normally, without defining hundreds of pygame-already-existing methods in my class?
And one another thing. If I do something by using my class, and I screw up, I always get this msg:
File "C:/Python35/game.py", line 23, in <module>
pygame.display.update()
pygame.error
And I actually don't know what the heck is wrong. If I do this normally, without classes, then I get erros such as, pygame object blabla has no method blablabla or something like that, I just know what's happening. Is there a way to get through this, and find what's going on?
Thanks in advance for your help!
What you are doing here is on the right track, but it is done the wrong way. Your main "game loop" should be inside the class itself as a method, rather than calling stuff from outside the class in an actual loop. Here is a basic example of what you should be doing.
# Load and initialize Modules here
import pygame
pygame.init()
# Window Information
displayw = 800
displayh = 600
window = pygame.display.set_mode((displayw,displayh))
# Clock
windowclock = pygame.time.Clock()
# Load other things such as images and sound files here
image = pygame.image.load("foo.png").convert # Use convert_alpha() for images with transparency
# Main Class
class MainRun(object):
def __init__(self,displayw,displayh):
self.dw = displayw
self.dh = displayh
self.Main()
def Main(self):
#Put all variables up here
stopped = False
while stopped == False:
window.fill((255,255,255)) #Tuple for filling display... Current is white
#Event Tasking
#Add all your event tasking things here
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN:
stopped = True
#Add things like player updates here
#Also things like score updates or drawing additional items
# Remember things on top get done first so they will update in the order yours is set at
# Remember to update your clock and display at the end
pygame.display.update()
windowclock.tick(60)
# If you need to reset variables here
# This includes things like score resets
# After your main loop throw in extra things such as a main menu or a pause menu
# Make sure you throw them in your main loop somewhere where they can be activated by the user
# All player classes and object classes should be made outside of the main class and called inside the class
#The end of your code should look something like this
if __name__ == __main__:
MainRun()
The main loop will call itself when the object MainRun() is created.
If you need more examples on specific things such as object handling let me know and I will see if I can throw some more information up for you.
I hope this helps you with your programming and the best of luck to you.
========================= EDIT ================================
In this case for these special operations make them object specific. Instead of using one generic method to blit your objects, make each object have its own function. This is done this way to allow for more options with each object you make. The general idea for the code is below... I have created a simple player object here.
#Simple player object
class Player(object):
def __init__(self,x,y,image):
self.x = x
self.y = y
self.image = image
#Method to draw object
def draw(self):
window.blit(self.image,(self.x,self.y))
#Method to move object (special input of speedx and speedy)
def move(self,speedx,speedy):
self.x += speedx
self.y += speedy
Now here is how you use the object's methods... I have included an event loop to help show how to use the move function. Just add this code to your main loop wherever it is needed and you will be all set.
#Creating a player object
player = Player(0,0,playerimage)
#When you want to draw the player object use its draw() method
player.draw()
#Same for moving the player object
#I have included an event loop to show an example
#I used the arrow keys in this case
speedx = 0
speedy = 0
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
speedy = -5
speedx = 0
elif event.key == pygame.K_DOWN:
speedy = 5
speedx = 0
elif event.key == pygame.K_RIGHT:
speedy = 0
speedx = 5
elif event.key == pygame.K_LEFT:
speedy = 0
speedx = -5
elif event.type == pygame.KEYUP:
speedx = 0
speedy = 0
#Now after you event loop in your object updates section do...
player.move(speedx,speedy)
#And be sure to redraw your player
player.draw()
#The same idea goes for other objects such as obstacles or even scrolling backgrounds
Be sure to use the same display name of the display inside your draw function.

Categories

Resources