Botonian
Botonian

Reputation: 87

Make Character Keep Moving While Key Held Down

I'm trying to make a quick animation where if a key is held down the character will keep moving, however my code doesn't seem to be doing that. I press the key and moves once but doesn't move any further. Any help to fix this. Any other suggestions are appreciated and keep in mind this isn't near final product form.

import pygame
import os
import sys
from pygame.locals import *


pygame.init()
WIN = pygame.display.set_mode(display)
pygame.display.set_caption('The Game')
width = 500
height = 500
display = (width, height)
WHITE = (255, 255, 255)

left = [
pygame.image.load(os.path.join('assets', 'main', 'left_walk1.png')),
pygame.image.load(os.path.join('assets', 'main', 'left_walk2.png'))
]

right = [
pygame.image.load(os.path.join('assets', 'main', 'right_walk1.png')),
pygame.image.load(os.path.join('assets', 'main', 'right_walk2.png'))
]

up = [
pygame.image.load(os.path.join('assets', 'main', 'up_walk1.png')),
pygame.image.load(os.path.join('assets', 'main', 'up_walk2.png'))
]

down = [
pygame.image.load(os.path.join('assets', 'main', 'down_walk1.png')),
pygame.image.load(os.path.join('assets', 'main', 'down_walk2.png'))
]

standing_left = (os.path.join('assets', 'main', 'down_walk2.png'))
standing_right = (os.path.join('assets', 'main', 'down_walk2.png'))
standing_up = (os.path.join('assets', 'main', 'down_walk2.png'))
standing_down = (os.path.join('assets', 'main', 'down_walk2.png'))




class Player:
  def __init__(self, x, y):

      self.x = x
      self.y = y
      self.health = 100
      self.inv = []
      self.left = False
      self.right = False
      self.up = False
      self.down = False
      self.walking_count = 0

      self.facing = 'down'

  def draw_player(self, win):

      if self.walking_count == 3:
          self.walking_count = 1

      if self.left:
          WIN.blit(left[self.walking_count // 2], (self.x, self.y))

      elif self.right:
          WIN.blit(right[self.walking_count // 2], (self.x, self.y))

player = Player(100, 100)

FPS = 40
fpsClock = pygame.time.Clock()

while True:
  fpsClock.tick(FPS)
  WIN.fill(WHITE)
  player.draw_player(WIN)

  for event in pygame.event.get():
      if event.type == QUIT:
          pygame.quit()
          sys.exit()
      elif event.type == KEYDOWN:
          if event.key == K_UP and player.y <= 0:
              player.up = True
          elif event.key == K_DOWN:
              player.down = True
          elif event.key == K_LEFT:
              player.left = True
          elif event.key == K_RIGHT:
              player.right = True
      elif event.type == KEYUP:
          if event.key == K_UP:
              player.up = False
          if event.key == K_DOWN:
              player.down = False
          if event.key == K_LEFT:
              player.left = False
          if event.key == K_RIGHT:
              player.right = False

      if player.left:
          player.x -= 5
          player.walking_count += 1
      if player.right:
          player.x += 5
          player.walking_count += 1
      if player.up:
          player.y -= 5
          player.walking_count += 1
      if player.down:
          player.y += 5
          player.walking_count += 1


  pygame.display.update()

Upvotes: 2

Views: 58

Answers (1)

Rabbid76
Rabbid76

Reputation: 211047

It is a matter of Indentation. You've to apply the movement in the application loop rather than the event loop:

while True:
    fpsClock.tick(FPS)
    WIN.fill(WHITE)
    player.draw_player(WIN)

    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            if event.key == K_UP and player.y <= 0:
                player.up = True
            elif event.key == K_DOWN:
                player.down = True
            elif event.key == K_LEFT:
                player.left = True
            elif event.key == K_RIGHT:
                player.right = True
        elif event.type == KEYUP:
            if event.key == K_UP:
                player.up = False
            if event.key == K_DOWN:
                player.down = False
            if event.key == K_LEFT:
                player.left = False
            if event.key == K_RIGHT:
                player.right = False

    #<--| INDENTATION
    if player.left:
        player.x -= 5
    if player.right:
        player.x += 5
    if player.up:
        player.y -= 5
    if player.down:
        player.y += 5

    pygame.display.update()

Alternatively you can use pygame.key.get_pressed() rather than the KEYDOWN and KEYUP event:

while True:
    fpsClock.tick(FPS)
    WIN.fill(WHITE)
    player.draw_player(WIN)

    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    keys = pygame.key.get_pressed()
    player.left, player.right, player.up, player.down = False, False, False, False
    if keys[K_LEFT]:
        player.x -= 5
        player.left = True
    if keys[K_RIGHT]:
        player.x += 5
        player.right = True
    if keys[K_UP]:
        player.y -= 5
        player.up = True
    if keys[K_DOWN]:
        player.y += 5
        player.down = True

    pygame.display.update()

To control the animation speed, add an attribute self.animation_frames = 10. This attributes controls how many frames each image of the animation is shown. Compute the image index dependent on the attribute.
walking_count has to be incremented in Player.draw_player rather than the application loop.
To ensure that the correct "standing" image is displayed, you have to add an attribute self.standing. Set the attribute dependent on the current direction in draw_player. If the player is not moving, the display the current standing image:

class Player:
    def __init__(self, x, y):
        # [...]

        self.animation_frames = 10
        self.standing = standing_left

    def draw_player(self, win):

        # get image list
        if self.left:
            image_list = left
            self.standing = standing_left
        else self.right:
            image_list = right
            self.standing = standing_right
        else:
            image_list = [self.standing]

        # increment walk count and get image list
        image_index = self.walking_count // self.animation_frames
        if image_index >= len(image_list):
            image_index = 0
            self.walking_count = 0
        self.walking_count += 1

        WIN.blit(image_list[image_index], (self.x, self.y))

Upvotes: 2

Related Questions