The main issue is that you process all the events in two places (the first is in the main loop and the second is in the player), the first one ignores the keydown event, and the second one misses it because the first one discarded it.
The first way you can patch this is by checking for the KEYDOWN event in the main loop and pass a flag to the Player.update() function:
(All code is untested.)
In Body:
while True:
player_moves_up = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
player_moves_up = True
player.update(player_moves_up)
screen.blit(final_background,background_rect)
player.draw(screen)
pygame.display.update()
clock.tick(FPS)
In Player:
# This function is no longer needed.
# def player_input(self, player_moves_up):
# for event in pygame.event.get():
# if event.type == pygame.KEYDOWN:
# if event.key == pygame.K_UP:
# self.rect.y -= 20
def update(self, player_moves_up):
if player_moves_up:
self.rect.y -= 20
Alternatively you can have you player class monitor for key value changes ("rising edge"), and act upon it.
In Player:
class Player(pygame.sprite.Sprite):
global x_position, y_position
x_position = 50
y_position = 400
def __init__(self):
super().__init__()
player_walk_1 = sprite_sheet.get_image(0, 24, 34, 3, GREEN_SCREEN_BACKGROUND)
player_walk_2 = sprite_sheet.get_image(1, 24, 34, 3, GREEN_SCREEN_BACKGROUND)
player_walk_3 = sprite_sheet.get_image(2, 24, 34, 3, GREEN_SCREEN_BACKGROUND)
player_walk = [player_walk_1, player_walk_2, player_walk_3]
player_walk_index = 0
self.image = player_walk_2
self.rect = self.image.get_rect(bottomleft = (x_position,y_position))
# This will track from frame to frame the state of the key
self.keyboard_state_move_up_pressed = False
# This will allow you to check that the key has just been pressed this frame
self.keyboard_state_move_up_just_pressed = False
def player_input(self):
# Reset the flag
self.keyboard_state_move_up_just_pressed = False
# Check if the key has just been pressed
new_keyboard_state_move_up_pressed = pygame.key.get_pressed()[pygame.K_UP]
if not self.keyboard_state_move_up_pressed and new_keyboard_state_move_up_pressed:
self.keyboard_state_move_up_just_pressed = True
# Store the key state for the next frame
self.keyboard_state_move_up_pressed = new_keyboard_state_move_up_pressed
def update(self):
self.player_input()
# You can now react to it based on the updated inpu.
if self.keyboard_state_move_up_just_pressed:
self.rect.y -= 20
The first "patch" approach has the advantage that you know which keys are used and you don't have to track the state yourself, and it can make your class easier to test because you "inject" the values to it, instead of having it rely on singletons, while the "second" approach has the handling more localized where you need it and "pollutes" less of the rest of the code.