You must implement bullet movement in the application loop, not in an additional loop within the event loop. Add a fired variable that indicates whether pressing SPACE fired the bullet. Move the bullet when the fired status is set. Reset fired when the bullet reaches the top of the screen:
fired = False
while run:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
fired = True
if fired:
player.bullet_rect.y -= bullet_velocity
if player.bullet_rect.y < 0:
fired = False
The general approach to firing bullets is to store the positions of the bullets in a list (bullet_list). When a bullet is fired, add a copy of the bullet rectangle to the list. The starting position is the position of the player. Use a for-loop to iterate through all the bullets in the list. Move position of each individual bullet in the loop. Remove a bullet from the list that leaves the screen (bullet_list.remove(bullet_pos)). For this reason, a copy of the list (bullet_list[:]) must be run through (see How to remove items from a list while iterating?). Use another for-loop to blit the remaining bullets on the screen:
bullet_list = []
while run:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# create bullet rectangle with the position of the player
bullet_rect =
bullet_list.append(bullet_rect)
for bullet_rect in bullet_list[:]:
bullet_rect.y += bullet_velocity
if bullet_rect.y < 0:
bullet_list.remove(bullet_rect)
# [...]
for bullet_rect in bullet_list[:]
# draw bullet at bullet_rect
# [...]