Python,Pygame, local variable referenced before assignment - python-3.x
Relatively new to Pygame. I'm trying to make a rectangle move from a character (xeon) like a bullet, horizontally when pressing the downarrow key. I keep getting this error.
"UnboundLocalError: local variable 'bullets' referenced before assignment"
Any feedback is much appreciated. Excuse the mess...........................
import pygame
import time
import random
import sys
import os
pygame.init()
display_width=800
display_height=600
black=(0,0,0)
white=(255,255,255)
red=(200,0,0)
green=(0,200,0)
blue=(0,0,200)
bright_green=(0,255,0)
bright_red=(255,0,0)
gameDisplay=pygame.display.set_mode((800,600))
pygame.display.set_caption("Xeongame")
clock=pygame.time.Clock()
zheImg=pygame.image.load("xeon.png").convert()
bgImg=pygame.image.load("Spacebackground.jpg").convert()
xeon_width=300
def xeon(x,y):
gameDisplay.blit(zheImg,(x,y))
def bullets(x,y,bx,by,bw,bh,color):
while True:
pygame.draw.rect(gameDisplay,color,[bx,by,bw,bh])
def quitgame():
pygame.quit()
quit()
def text_objects(text,font):
textSurface=font.render(text,True,black)
return textSurface,textSurface.get_rect()
def obstacles(obstaclex,obstacley,obstaclew,obstacleh,color):
pygame.draw.rect(gameDisplay,color,[obstaclex,obstacley,obstaclew,obstacleh])
def message_display(text):
largeText=pygame.font.Font("freesansbold.ttf",115)
TextSurf,TextRect=text_objects(text,largeText)
TextRect.center=((display_width/2),(display_height/2))
gameDisplay.blit(TextSurf,TextRect)
pygame.display.update()
time.sleep(1)
game_loop()
def button(msg,x,y,w,h,ic,ac,action=None):
mouse=pygame.mouse.get_pos()
click=pygame.mouse.get_pressed()
if x+w>mouse[0]>x and y+h>mouse[1]>y:
pygame.draw.rect(gameDisplay,ac,(x,y,w,h))
if click[0]==1 and action !=None:
action()
if action=="Play":
game_loop()
elif action=="Quit":
pygame.quit()
quit()
else:
pygame.draw.rect(gameDisplay,ic,(x,y,w,h))
smallText=pygame.font.Font("freesansbold.ttf",20)
textSurf,textRect=text_objects(msg,smallText)
textRect.center=( (x+(w/2)),(y+(h/2)) )
gameDisplay.blit(textSurf,textRect)
largeText=pygame.font.Font("freesansbold.ttf",115)
def game_intro():
intro=True
while intro:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
largeText=pygame.font.Font("freesansbold.ttf",115)
TextSurf,TextRect=text_objects("Xeon",largeText)
TextRect.center=((display_width/2),(display_height/2))
gameDisplay.blit(TextSurf,TextRect)
xeon(10,100)
button("Play",150,450,100,50,green,bright_green,game_loop)
button("Quit",550,450,100,50,red,bright_red,quitgame)
pygame.display.update()
clock.tick(15)
def game_loop():
x=(display_width*.10)
y=(display_height*0.50)
x_change=0
y_change=0
x+=x_change
y+=y_change
##ALTERNATIVE JUMPING
#xeon_gravity=0.8
#xeon_acc=0.5
obstacle_speed=7
obstacle_height=100
obstacle_width=50
obstacle_startx=random.randrange(300,display_width)
obstacle_starty=-100
##bullets
bullets_height=10
bullets_width=50
bullets_startx=xeon_width
bullets_starty=xeon_width
bullets_speed=0.7
bullets_x_change=0
####KEYS
gameExit=False
while not gameExit:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
quit()
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_RIGHT:
x_change=-5
if event.key==pygame.K_LEFT:
x_change=+5
if event.key==pygame.K_UP:
y_change=-5
if event.key==pygame.K_DOWN:
bullets=True
pygame.draw.rect(gameDisplay,[bx,by,bw,bh,color])
bullets_x_change=-5
if event.type==pygame.KEYUP:
if event.key==pygame.K_LEFT or event.key==pygame.K_RIGHT:
x_change=0
x+=x_change
y+=y_change
rel_x=x%bgImg.get_rect().width
gameDisplay.blit(bgImg,(rel_x-bgImg.get_rect().width,0))
gameDisplay.blit(bgImg,(rel_x,0))
xeon(x_change,y)
bullets(bullets_startx,bullets_starty,bullets_width,bullets_height,blue)
bullets_starty+=bullets_speed
obstacles(obstacle_startx,obstacle_starty,obstacle_width,obstacle_height,red)
obstacle_starty+=obstacle_speed
if obstacle_starty>display_height:
obstacle_starty=0-obstacle_height
obstacle_startx=random.randrange(300,display_width)
pygame.display.update()
clock.tick(60)
game_intro()
game_loop()
pygame.quit()
quit()
The problem is that you have a local variable named bullets (in the game_loop function) and a global function with the same name. When you call the function bullets() in game_loop, Python thinks you mean the local variable to which you haven't assigned anything yet, so the UnboundLocalError is raised.
Rename the function or the variable to avoid the UnboundLocalError.
Here's an answer with more information.
You're also not passing enough arguments to the bullets function.
Related
How to run time.sleep() without stopping while loop
Is there a way to call a function which has wait(time.sleep()) from infinite while loop without disturbing the loop? I am trying to run a few task that require to wait for a few seconds but the issue is that the while loop also stops when the wait process is happening. This is what I have tried out- Here is my code: import cv2 import time def waiting(): print("Inside function") # Running Some Tasks time.sleep(5) print("Done sleeping") def main(): cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() cv2.imshow("Webcam", frame) k = cv2.waitKey(10) if k == 32: # Press SPACEBAR for wait function waiting() elif k == 27: # Press ESC to stop code break cap.release() cv2.destroyAllWindows() if __name__ == "__main__": main()
Thanks for the quick responses from #JLT and #TerePiim. Here is the updated code for anyone who might benefit from this: import cv2 import time import threading def waiting(): print("Inside parallel function") # Running some Tasks time.sleep(5) print("Done sleeping") def main(): cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() cv2.imshow("Webcam", frame) k = cv2.waitKey(10) if k == 32: # Press SPACEBAR for wait function t = threading.Thread(target=waiting) t.start() elif k == 27: # Press ESC to stop code break cap.release() cv2.destroyAllWindows() if __name__ == "__main__": main()
You are working in a single thread script at the moment. You should use threading or multiprocessing. This makes (it look like) multiple processes (are) active. Dependent on if you use threading or multiprocessing.
You should use threads. It will look like the computer is doing them both at the same time. import threading t = threading.Thread(target=function) t.start()
How to use event.value for another function outside of the main loop? [duplicate]
This question already has answers here: How to run multiple while loops at a time in Pygame (1 answer) Spawning multiple instances of the same object concurrently in python (1 answer) Closed 1 year ago. Below is a working skeleton of my actual code. What I am attempting to do is to obtain the JOYAXISMOTION, event.value, y so that I can use it in different function outside of the loop. I have already defined the variable y. import time import sys import pygame import subprocess import random from pygame.locals import * pygame.init() y = 0 def get_percent_change(current, previous): if current == previous: return 0 try: return ((float(current) - float(previous)) /abs(previous)) * 100.0 except ZeroDivisionError: return float('inf') def sendCommands(): time.sleep(5) print('Hello World') pygame.joystick.init() joysticks = [pygame.joystick.Joystick(i) for i in range(pygame.joystick.get_count())] for joystick in joysticks: print(joystick.get_name()) game_state = False run = True while run: for event in pygame.event.get(): if event.type == JOYBUTTONDOWN: print(event) if game_state == False and event.button == 8: game_state = True if event.button == 4: game_state = False if event.type == JOYHATMOTION: if event.value[0] == 1 or event.value[0] == -1: game_state = False if event.type == JOYAXISMOTION: if event.axis == 4: current = event.value y = get_percent_change(current, -1.0001) print(y) if event.type == JOYDEVICEADDED: joysticks = [pygame.joystick.Joystick(i) for i in range(pygame.joystick.get_count())] for joystick in joysticks: print(joystick.get_name()) if event.type == JOYDEVICEREMOVED: joysticks = [pygame.joystick.Joystick(i) for i in range(pygame.joystick.get_count())] if game_state == True: sendCommands() pygame.quit() sys.exit() The main problem I am running into is the time.sleep(5) that the sendCommands requires. It is blocking the script while sleeping. I have tried asyncio with no success. Threading is also very confusing to me here. I have also tried the delay logic in the answer provided to a closely related question here but that also blocks the code from running. Allow me to pick your brain on how: I can run the script without it being blocked and how I can access and use the event.value, y outside of the loop
To use y outside of the loop, you could declare it as global but a better alternative is to make a function to get the value. You can implement a timer to execute your subprocess every 5 seconds instead of blocking the entire thread. The following code prints None every 5 seconds for me since I don't have any controllers connected but I think it will work for you. import time import sys import pygame from pygame.locals import * pygame.init() def sendCommands(waitTime, y): global sendCommandsStart #count how many seconds have passed since sendCommandsStart #variable was last updated if time.time() - sendCommandsStart > waitTime: sendCommandsStart = time.time() #reset the timer print(y)#call your subpreocess here def getJoyStickY(events): for event in events: if event.type == JOYAXISMOTION: if event.axis == 4: return get_percent_change(current, -1.0001) return None pygame.joystick.init() run = True sendCommandsStart = time.time() #get the current time - its just a number (time since last epoh) while run: allEvents = pygame.event.get() sendCommands(5, getJoyStickY(allEvents)) pygame.quit() sys.exit()
Same pygame event generated over and over
In my pygame application, I want a web browser to open when the user presses the F1 key: #!/usr/bin/env python3 import pygame as pg import webbrowser pg.init() screen = pg.display.set_mode((400, 400)) pg.key.set_repeat(200, 100) while True: for evt in pg.event.get(): if evt.type == pg.KEYDOWN and evt.key == pg.K_F1: webbrowser.open('http://some-website.com') pg.quit() When pressing F1, the browser opens but my application keeps opening new tabs if I don't kill it. My guess is that the same KEYDOWN event is generated over and over when my application loses the focus due to the use of pg.key.set_repeat: if I comment this call to pg.key.set_repeat then everything works fine. How can I fix that? Versions used are: pygame 2.0.1 (SDL 2.0.14, Python 3.9.5).
You should use keyboard module like this: import keyboard # [...] while True: # [...] if keyboard.is_pressed("F1"): webbrowser.open('http://some-website.com') pg.quit() Or you can break the loop after you open the spesific website: # [...] while True: for evt in pg.event.get(): if evt.type == pg.KEYDOWN and evt.key == pg.K_F1: webbrowser.open('http://some-website.com') break # [...] pg.quit()
Stop mouse event when pressing key
My code uses mouse events to send messages but I have no idea how to stop using an f1 key. I didn't find a stop () method as in Listener () in Events (). import pynput import pyautogui import time from pynput import mouse from pynput import keyboard running = True mouse_event = mouse.Events() def on_press(key): global running if key == keyboard.Key.f1: running = False print('end') return False def msg(): mouse_event.start() for event in mouse_event: if running: if isinstance(event,mouse.Events.Click): if not event.pressed: pyautogui.typewrite('hello world\n',interval=0.009) else: time.sleep(1) return False while 1: print("Choose the desired option") print("1. Message") option = int(input("Option:")) if option == 1: running = True with keyboard.Listener(on_press=on_press) as listener: if running: msg() elif not listener.running: time.sleep(2) break Is there a way to interrupt a mouse event with the press of a key? One attempt was to pass the method as on_press to Events () does not work.
I've had to do something similar in the past and I ended up using threading to have one thread listen for the mouse/keyboard input while the other runs my main program. import time from pynput import keyboard from threading import Thread def exit_program(): def on_press(key): if str(key) == 'Key.f1': main.status = 'pause' user_input = input('Program paused, would you like to continue? (y/n) ') while user_input != 'y' and user_input != 'n': user_input = input('Incorrect input, try either "y" or "n" ') if user_input == 'y': main.status = 'run' elif user_input == 'n': main.status = 'exit' exit() with keyboard.Listener(on_press=on_press) as listener: listener.join() def main(): main.status = 'run' while True: print('running') time.sleep(1) while main.status == 'pause': time.sleep(1) if main.status == 'exit': print('Main program closing') break Thread(target=main).start() Thread(target=exit_program).start()
how to fix Python pep 8 recommendations with pygame constants
I have a problem with pep 8 and my Python code concerning Pygame constant on the next piece of code, which is sending me error E0602 "Undefined variable" when i use the pygame constant "KEYDOWN" "K_F1" K_ESCAPE" is there any trick to solve this problem with pep8 I am a beginner and I admit that I do not find a solution to solve this problem :( def run(self): """ start loop """ loop = True while loop is True: self.windowSurface.blit(self.Sprite.home, (0, 0)) self.pygame.display.flip() for event in pygame.event.get(): if event.type == KEYDOWN: if event.key == K_F1: loop = False elif event.key == K_ESCAPE: sys.exit(1)
Adding pygame. in front of those constants should fix the PEP8 issue. In your case, pygame.KEYDOWN, pygame.K_F1, and pygame.K_ESCAPE.