Skip to main content
added 72 characters in body
Source Link
Vaillancourt
  • 16.4k
  • 17
  • 56
  • 61

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 keydownKEYDOWN event, and the second one misses it because the first one discarded it. The code for event in pygame.event.get(): is responsible for this.

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 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 code for event in pygame.event.get(): is responsible for this.

added 1 character in body
Source Link
Vaillancourt
  • 16.4k
  • 17
  • 56
  • 61
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 inpuinput.
        if self.keyboard_state_move_up_just_pressed:
            self.rect.y -= 20
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
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 input.
        if self.keyboard_state_move_up_just_pressed:
            self.rect.y -= 20
Source Link
Vaillancourt
  • 16.4k
  • 17
  • 56
  • 61

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.