I have a problem moving the objects continuously while pressing a key.
As far as I know, pygame events only trigger when receiving a new signal and that the key pressed is not a signal that continues with every frame. From the code below, when I press w for example, the object only moves when pressing and when releasing the key. I can't achieve the object to move as long as I keep pressing the key. I've also tried out the if statements by checking event.key instead of checking the get_pressed() list, but I came up with the same result.
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
keys = pygame.key.get_pressed()
print(keys[pygame.K_w])
if keys[pygame.K_w] and keys[pygame.K_d]:
x_change = 3
x += x_change
y_change = -3
y += y_change
elif keys[pygame.K_w] and keys[pygame.K_a]:
x_change = -3
x += x_change
y_change = -3
y += y_change
elif keys[pygame.K_s] and keys[pygame.K_d]:
x_change = 3
x += x_change
y_change = 3
y += y_change
elif keys[pygame.K_s] and keys[pygame.K_a]:
x_change = -3
x += x_change
y_change = 3
y += y_change
elif keys[pygame.K_a]:
x_change = -3
x += x_change
elif keys[pygame.K_d]:
x_change = 3
x += x_change
elif keys[pygame.K_w]:
y_change = -3
y += y_change
elif keys[pygame.K_s]:
y_change = 3
y += y_change
#ERASE OLD
screen.fill(WHITE)
#FILL NEW
all_sprites_list.draw(screen)
wall.changePosition(x,y)
player.draw(start_x,start_y)
pygame.display.update()
clock.tick(60)
It looks like the line keys = pygame.key.get_pressed() and the following lines are in your event loop, and that means they are only executed once per event in the event queue. They should actually be in the outer while loop, so just dedent these lines:
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
keys = pygame.key.get_pressed()
if keys[pygame.K_w] and keys[pygame.K_d]:
x_change = 3
# etc.
You can also shorten your code quite a bit:
x_change = 3
y_change = 3
crashed = False
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
x += -x_change
elif keys[pygame.K_d]:
x += x_change
if keys[pygame.K_w]:
y += -y_change
elif keys[pygame.K_s]:
y += y_change
Another alternative would be to remove the key.get_pressed lines and just set the x_change and y_change in the event loop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
x_change = 3
# etc.
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d and x_change > 0:
x_change = 0
# etc.
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
When running the game loop the game tends to crash when using the arrow keys to move a game object. The error seems to occur at an undetermined point.
Python throws the error :
Exception has occurred: UnboundLocalError
local variable 'event' referenced before assignment
I've tried to make a function for the controls and call them but this doesn't work. I've tried to indent the logic into: for event in pygame.event.get(): but then the object cannot be controlled.
def game_loop(): # The game loop which runs the core mechanics of the game
x = (display_width * 0.5) # Initial x/y values of the circle, where it is placed
y = (display_height * 0.6)
dx = 0 #Change in those x,y values
dy = 0
thing_startx = random.randrange(0,display_width)
thing_starty = random.randrange(0,display_height)
thing_speed = 7
thing_width = random.randrange(50,500)
thing_height = 100
gameExit = False #This becomes true if the player wants to exit the game
while not gameExit: # game loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
print(event)
if event.type == pygame.KEYDOWN: # if a key is pressed down
if event.key == pygame.K_LEFT: # if it is the left arrow key
dx = -5 #change x by -5 (go left)
elif event.key == pygame.K_RIGHT:
dx = 5
if event.type == pygame.KEYUP: # if key is released
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT: #if neither left or right arrow keys are pressed,
dx = 0 #Do not change x
x += dx #x+dx. add the change to the original
if event.type == pygame.KEYDOWN: #as above but for y axis
if event.key == pygame.K_UP:
dy = -5
elif event.key == pygame.K_DOWN:
dy = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
dy = 0
y += dy
gameDisplay.fill(darkGreen)#paint the display white
#things (thingx,thingy,thingw,thingh,colour)
things(thing_startx,thing_starty,thing_width,thing_height,red)
thing_starty += thing_speed
circle(x,y) # paint the circle into the display at x,y
#Boundaries
if x > display_width - circleWidth or x<0:
crash()#Call crash function if boundaries are met
elif y >display_height - circleHeight or y<0:
crash()
if thing_starty > display_height:
thing_starty = 0 - thing_height
thing_startx = random.randrange(0,display_width)
#Detects collisions with obstacles in the road
if y < thing_starty+thing_height:
print('y crossover')
if x > thing_startx and x < thing_startx + thing_width or x + circleWidth > thing_startx and x + circleWidth < thing_startx+thing_width:
print('x crossover')
#crash()
pygame.display.update() #update the display
clock.tick(60)#make game 60fps
Here is the error:
Exception has occurred: UnboundLocalError
local variable 'event' referenced before assignment
File "C:\Python\pythonWorkspace\Tutorial.py", line 131, in game_loop
if event.type == pygame.KEYDOWN: # if a key is pressed down
File "C:\Python\pythonWorkspace\Tutorial.py", line 73, in button
game_loop()
File "C:\Python\pythonWorkspace\Tutorial.py", line 101, in game_intro
button("GO",150,450,100,50,green,brightGreen,"play")
File "C:\Python\pythonWorkspace\Tutorial.py", line 180, in <module>
game_intro()# call the game intro screen
This is an issue of Indentation. The code which handles the events and the check of the event type (e.g. event.type == pygame.KEYDOWN) has to be done in the event loop rather than the main game loop:
def game_loop(): # The game loop which runs the core mechanics of the game
# [...]
while not gameExit: # game loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
#
# --> INDENTATION: the following code has to be in the event loop
#
if event.type == pygame.KEYDOWN: # if a key is pressed down
if event.key == pygame.K_LEFT: # if it is the left arrow key
dx = -5 #change x by -5 (go left)
elif event.key == pygame.K_RIGHT:
dx = 5
if event.type == pygame.KEYUP: # if key is released
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
#if neither left or right arrow keys are pressed,
dx = 0 #Do not change x
if event.type == pygame.KEYDOWN: #as above but for y axis
if event.key == pygame.K_UP:
dy = -5
elif event.key == pygame.K_DOWN:
dy = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
dy = 0
# this code has to be in the main game loop
x += dx
y += dy
But you can simplify the code by the use of pygame.key.get_pressed():
def game_loop(): # The game loop which runs the core mechanics of the game
# [...]
while not gameExit: # game loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
keys = pygame.key.get_pressed()
dx = -5 if keys[pygame.K_LEFT] else 5 if keys[pygame.K_RIGHT] else 0
dy = -5 if keys[pygame.K_UP] else 5 if keys[pygame.K_DOWN] else 0
x += dx
y += dy
My name is Jeremy and I am learning Python. I am a beginner and I just started a couple of days ago.
I am making a simple game in Python, and I would like my block/player to move continuously while the respective arrow key is held down. As of now, it only moves once when pressing down the arrow keys. Any help is greatly appreciated. Thank you!
Here is the code I've written:
import pygame
import time
import random
pygame.init()
display_width = 800
display_height = 600
black = (0,0,0)
white = (255,255,255)
red = (200,0,0)
green = (0,200,0)
bright_red = (255,0,0)
bright_green = (0,255,0)
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Game')
clock = pygame.time.Clock()
blockImg = pygame.image.load('blockpic.png')
def block(x,y):
gameDisplay.blit(blockImg, (x,y))
x = (display_width * 0.45)
y = (display_height * 0.8)
x_change = 0
y_change = 0
crashed = False
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -10
if event.key == pygame.K_RIGHT:
x_change = 10
if event.key == pygame.K_UP:
y_change = -10
if event.key == pygame.K_DOWN:
y_change = 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
if event.key == pygame.K_DOWN or event.key == pygame.K_UP:
y_change = 0
x += x_change
y += y_change
gameDisplay.fill(white)
block(x,y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
Your code is not indented correctly. The line x += x_change and the five lines beneath are inside of the event loop, so they get executed once per event in the event queue. Just dedent these lines to fix the program.
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -10
if event.key == pygame.K_RIGHT:
x_change = 10
if event.key == pygame.K_UP:
y_change = -10
if event.key == pygame.K_DOWN:
y_change = 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
if event.key == pygame.K_DOWN or event.key == pygame.K_UP:
y_change = 0
# The following lines should be executed once per frame not
# once per event in the event queue.
x += x_change
y += y_change
gameDisplay.fill(white)
block(x,y)
pygame.display.update()
clock.tick(60)
I am trying to make a game, but you can keep spamming "w" (jump) for infinite height which is really bad when you are trying to make a platformer game. This is all my code:
GRAVITY = .2
diedorgameover = False
while not diedorgameover:
for event in pygame.event.get():
if event.type == pygame.QUIT:
diedorgameover = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
x_change = -5
elif event.key == pygame.K_d:
x_change = 5
elif event.key == pygame.K_s:
y_change = 5
elif event.key == pygame.K_w:
y_change = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_a or event.key == pygame.K_d:
x_change = 0
if event.key == pygame.K_s or event.key == pygame.K_w:
y_change = 0
#adding gravity to y_value
y_change += GRAVITY
x += x_change
y += y_change
if y >= gameDisplay.get_height() - 68:
y = gameDisplay.get_height() - 68
y_change = 0
#draw everything
gameDisplay.blit(background_image,(0,0))
red(x,y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
I would really appreciate it if you have any insight on this problem.
You can define a on_ground variable that you set to True if the player touches the ground. When the user wants to jump (presses 'w') you first check if on_ground: and then change the y_change and set on_ground to False.
import pygame
pygame.init()
gameDisplay = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
GRAVITY = .5
player_img = pygame.Surface((30, 50))
player_img.fill((40, 120, 200))
x = 100
y = 500
x_change = 0
y_change = 0
on_ground = False
diedorgameover = False
while not diedorgameover:
for event in pygame.event.get():
if event.type == pygame.QUIT:
diedorgameover = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
x_change = -5
elif event.key == pygame.K_d:
x_change = 5
elif event.key == pygame.K_s:
y_change = 5
elif event.key == pygame.K_w:
# Only jump if the player is on the ground.
if on_ground:
y_change = -12
on_ground = False
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a or event.key == pygame.K_d:
x_change = 0
y_change += GRAVITY
x += x_change
y += y_change
# If the player is on the ground.
if y >= gameDisplay.get_height() - 68:
y = gameDisplay.get_height() - 68
y_change = 0
on_ground = True
gameDisplay.fill((30, 30, 30))
gameDisplay.blit(player_img, (x, y))
pygame.display.update()
clock.tick(60)
pygame.quit()
Also delete these lines, otherwise the player can stop while in the air if the key is released:
if event.key == pygame.K_s or event.key == pygame.K_w:
y_change = 0
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_SPACE and y_change == 0: # if spacebar is pressed and y_change is 0
y_change = 18 # set y_change to 18
if y_change > 0 and player_y == 200: # if y_change is greater than 0 and player_y is 200
player_y -= y_change
y_change -= gravity
if player_y > 200:
player_y = 200
if player_y == 200 and y_change < 0:
y_change = 0
So I'm just making a simple game that allows a red rectangle to move around the screen, but the boundaries that should make the red rectangle stop before it gets off the screen won't work. Can someone tell me what I'm doing wrong?
while Game:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
gameDisplay = pygame.display.set_mode((display_width,display_height), pygame.FULLSCREEN)
if event.key == pygame.K_2:
gameDisplay = pygame.display.set_mode((display_width,display_height))
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:
y_change = 5
if x > display_width - 100 or x < 0 and event.key == pygame.K_RIGHT:
if event.key == pygame.K_LEFT:
x_change = -5
else:
x_change = 0 #I did this for all directions
x += x_change
y += y_change
Just so you know, clock.tick is 80 and I have imported pygame and did the pygame.init() thing. Also, movement and every thing else works, just not this.
Try this code:
def clamp(value, minimum=0, maximum=1): return max(minimum, min(value, maximum))
maxX = display_width-rectangle_width
maxY = display_height-rectangle_height
if x not in range(maxX): x_change = 0
if y not in range(maxY): y_change = 0
x = clamp(x, maximum=maxX)
y = clamp(y, maximum=maxY)
However, you are changing the velocity and not the position, when it is out of the screen, the velocity is not moving it back, it keeps there or the speed from the pressed key in the next frame moves it again.
Basically I am trying to add some boundaries to a small game I am making, I have a sprite which can only move left to right and I am trying to prevent it from it from moving off the game window, if the sprite reaches the edge they can go no further and can then go in the opposite direction.
My current code:
tankSprite = pygame.image.load('Sprites/Tank.png') #fixed apostrophe
tankSprite_width = 28
def tank(x,y):
gameWindow.blit(tankSprite, (x,y))
def game_loop():
x = (display_width * 0.45)
y = (display_height * 0.8)
x_change = 0
gameExit = False
gameMove = True
while not gameExit and gameMove == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = False
if event.type ==pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
if event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFTor event.key == pygame.K_RIGHT:
x_change = 0
x += x_change
gameWindow.fill(white)
tank(x,y)
if x > display_width - tankSprite_width or x < 0:
gameMove = False
elif x < display_width - tankSprite_width or x > 0:
gameMove = True
pygame.display.update()
clock.tick(60)
game_loop()
pygame.quit()
quit()
My current code partially works, when the sprite reaches the edge the solution closes itself rather than letting me go back. If I remove:
pygame.quit()
quit()
Then the sprite just stops and I can't move it back. In a project I did a while back I used something like:
if event.key == pygame.K_LEFT and sprite.x < 590:
sprite.x += 5
The above code worked well from what I can remember but I can't seem to figure it out for my project now, can anyone help me out please?
I wish to make it so that the sprite can't go past the screen border, when the player reaches the border they either stay or go back in the opposite direction. Thanks
p.s. Sorry about the dodgy formatting
Just split your if-statement and check the condition for each direction separately:
tankSprite = pygame.image.load('Sprites/Tank.png')
tankSprite_width = 28
def tank(x,y):
gameWindow.blit(tankSprite, (x,y))
def game_loop():
x = (display_width * 0.45)
y = (display_height * 0.8)
x_change = 0
gameExit = False
gameMove = True
while not gameExit and gameMove == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = False
if event.type ==pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
if event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFTor event.key == pygame.K_RIGHT:
x_change = 0
#valid move, add x_change
if((x+x_change)> 0 and (x+x_change)<(display_width - tankSprite_width):
x += x_change
gameWindow.fill(white)
tank(x,y)
#deleted stuff here
pygame.display.update()
clock.tick(60)
game_loop()
pygame.quit()
quit()
With this method, you don't need to even use the gameMove variable anymore.
You could also get rid of the x_change variable entirely by simply applying the changes directly to x instead.
Also, I think you may have meant gameExit = True under the if statement if event.type == pygame.QUIT:, as it makes sense to exit when event pygame.QUIT is triggered.