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.

Resources