Search code examples
pythonpygame

Pygame KEYDOWN Arrow Keys resulting in player getting "stuck" during movement


Problem: Hi, I'm running into an issue where I'm trying to update my player (mario)'s position with the keyboard arrow keys (K_LEFT, K_RIGHT, etc.). The movements work as intended but the movements erratically get "stuck" in that my player can't move anymore unless I hit the key again. My player again resumes normal movement in the 4 arrow directional moves but then gets stuck again randomly soon after unless I double-hit the same key (or another key) to make it move again.

Contextual Info: I incorporated the "self.pause" because I wanted a way to stop the player rect from continuing to move after a KEYUP and I release the arrow keyboard key. The "self.move_left", "self.move_right", etc. are all boolean variables and the "self.move_rate" is an arbitrary numerical value.

Debugging so far: I wrote some print statements to figure out what was going on (and removed some of them to avoid clutter). I see that the branches within the code snippets go as expected. For example, I might be pressing K_DOWN to go down and then it would get "stuck" but my print statement would tell me that my boolean "self.move_down" is True and "self.pause" is False (meaning I can move) and that I'm currently within the branch underneath "if self.move_down" in the move() function.

Thank you for your help

    for event in pygame.event.get():
        if event.type == QUIT:
            terminate()
        if event.type == KEYDOWN:
            mario.pause = False
            if event.key == K_LEFT:
                mario.move_left, mario.move_right, mario.move_up, mario.move_down = True, False, False, False
            elif event.key == K_RIGHT:
                mario.move_left, mario.move_right, mario.move_up, mario.move_down = False, True, False, False
            elif event.key == K_UP:
                mario.move_left, mario.move_right, mario.move_up, mario.move_down = False, False, True, False
            elif event.key == K_DOWN:
                mario.move_left, mario.move_right, mario.move_up, mario.move_down = False, False, False, True
        elif event.type == KEYUP:
#            if event.key == K_LEFT:
#                mario.move_left = False
#            if event.key == K_RIGHT:
#                mario.move_right == False
#            if event.key == K_UP:
#                mario.move_up == False
#            if event.key == K_DOWN:
#                move_down == False
            mario.pause = True

And the other relevant code snippet

def move(self, window_surface):
    if not self.pause:
        #print(f"""status: pause->{self.pause} up -> {self.move_up}, down -> {self.move_down} left -> {self.move_left}  right -> {self.move_right}""")
        if self.move_left:
            #self.body.left -= self.move_rate
            self.body.move_ip(-1 * self.move_rate, 0)
        if self.move_right:
            #self.body.left += self.move_rate
            self.body.move_ip(self.move_rate, 0)
        if self.move_up:
            #self.body.top -= self.move_rate
            self.body.move_ip(0, -1 * self.move_rate)
        if self.move_down:
            #self.body.top += self.move_rate
            self.body.move_ip(0, self.move_rate)
    self.body.clamp_ip(window_surface.get_rect())

Solution

  • If you want to implement continuous movement, use pygame.key.get_pressed(), rather than the keyboard events:

    for event in pygame.event.get():
        if event.type == QUIT:
            terminate()
    
    keys = pygame.key.get_pressed()
    mario.move_left  = keys[K_LEFT]  and not keys[K_RIGHT]
    mario.move_right = keys[K_RIGHT] and not keys[K_LEFT]
    mario.move_up    = keys[K_UP]    and not keys[K_DOWN]
    mario.move_down  = keys[K_DOWN]  and not keys[K_UP]
    
    # [...]