Smooth Movement with pygame states

Question:

I’m currently working on a project, which basically is creating the pokemon game with pygame. To do so, I adapted an online code that consisted on game states (https://python-forum.io/Thread-PyGame-Creating-a-state-machine) I created a game state where the user will move the sprite with wads keys, the problem is that, although it does detect the key pressed and moves the sprite, it doesn’t detect when the key is being held and moves only 5 pixels the sprite(id does not continue to move, it gets stuck).
I tried moving the sprite movement code into the control class but I had the same problem, I think that it could be because the loop in which it’s located interrupts the movement. I’d really appreciate the help here.
HereĀ“s the Control Class code:

From player import * 
import pygame as pg
bg = pygame.image.load("imgs/bg_prueba.jpg")
class Control:
    def __init__(self):
        self.done = False
        self.fps = 60
        self.screen = pg.display.set_mode(bg.get_rect().size)
        self.screen_rect = self.screen.get_rect()
        self.clock = pg.time.Clock()

        """ CREATE TRAINER """
        motor = Motor()
        self.trainer = player(40, 40, motor.pokedex(), self.screen)

    def setup_states(self, state_dict, start_state):
        self.state_dict = state_dict
        self.state_name = start_state
        self.state = self.state_dict[self.state_name]

    def flip_state(self):
        self.state.done = False
        previous, self.state_name = self.state_name, self.state.next
        self.state.cleanup()
        self.state = self.state_dict[self.state_name]
        self.state.startup()
        self.state.previous = previous

    def update(self, dt):
        if self.state.quit:
            self.done = True
        elif self.state.done:
            self.flip_state()
        self.state.update(self.screen, dt)

    def event_loop(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.done = True
            self.state.get_event(event)

    def main_game_loop(self):
        while not self.done:
            delta_time = self.clock.tick(self.fps) / 1000.0
            self.event_loop()
            self.update(delta_time)
            pg.display.update()

And this is the Game State code:

from States import *
from Gym import *
from Control import *
gyms = [Gym(pygame.image.load("imgs/gym1.png"), 150,5)]
bg = pygame.image.load("imgs/bg_prueba.jpg")
class Map(States):
    def __init__(self):
        States.__init__(self)
        self.next = 'menu'

    def cleanup(self):
        print('cleaning up Game state stuff')

    def startup(self):
        print('starting Game state stuff')

    def get_event(self, event):
        clock.tick(20)
        if event.type == pg.KEYDOWN:
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                self.trainer.x -= self.trainer.v
                self.trainer.right = False
                self.trainer.left = True
                self.trainer.down = False
                self.trainer.up = False
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                self.trainer.x += self.trainer.v
                self.trainer.right = True
                self.trainer.left = False
                self.trainer.down = False
                self.trainer.up = False
            if event.key == pygame.K_UP or event.key == ord('w'):
                self.trainer.y -= self.trainer.v
                self.trainer.right = False
                self.trainer.left = False
                self.trainer.down = False
                self.trainer.up = True
            if event.key == pygame.K_DOWN or event.key == ord('s'):
                self.trainer.y += self.trainer.v
                self.trainer.right = False
                self.trainer.left = False
                self.trainer.down = True
                self.trainer.up = False

    def update(self, screen, dt):
        global walkCount
        screen.blit(bg, (0, 0))
        self.trainer.draw()
        gyms[0].draw(screen)
        pygame.display.update()

And the Trainer code for any possible doubts

from Motor import *
walkDown = [pygame.image.load("imgs/run_down1.png"), pygame.image.load("imgs/run_down2.png")]
walkUp = [pygame.image.load("imgs/run_up1.png"), pygame.image.load("imgs/run_up2.png")]
walkLeft = [pygame.image.load("imgs/run_left1.png"), pygame.image.load("imgs/run_left2.png")]
walkRight = [pygame.image.load("imgs/run_right1.png"), pygame.image.load("imgs/run_right2.png")]
stand = pygame.image.load("imgs/stand.png")
clock = pygame.time.Clock()
class player():
    def __init__(self, x, y, pokedex, screen):
        self.x = x
        self.y = y
        self.pokedex = pokedex
        self.right = False
        self.left = False
        self.up = False
        self.down = False
        self.v = 5
        self.width, self.height = stand.get_size()
        self.rect = (self.x, self.y, self.width, self.height)
        self.x2 = x + self.width
        self.y2 = y + self.height
        self.screen = screen
    def draw(self):
        self.screen.blit(stand, (self.x, self.y))
        if self.left:
            self.screen.blit(walkLeft[0], (self.x, self.y))
            self.screen.blit(walkLeft[1], (self.x, self.y))
        elif self.right:
            self.screen.blit(walkRight[0], (self.x, self.y))
            self.screen.blit(walkRight[1], (self.x, self.y))
        elif self.up:
            self.screen.blit(walkUp[0], (self.x, self.y))
            self.screen.blit(walkUp[1], (self.x, self.y))
        elif self.down:
            self.screen.blit(walkDown[0], (self.x, self.y))
            self.screen.blit(walkDown[1], (self.x, self.y))
        else:
            self.screen.blit(stand, (self.x, self.y))
        self.rect = (self.x, self.y, self.width, self.height)
        pygame.draw.rect(self.screen, (255, 0, 0), self.rect, 2)
Asked By: Lemm

||

Answers:

KEYDOWN and KEYUP event occur only once when a key is pressed. I recommend to gent the current sates of the keys by pygame.key.get_pressed(), to achieve a continuously smooth movement. e.g:

class Control:
    # [...]

    def event_loop(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.done = True
            self.state.get_event(event)
        self.state.get_keys()
class Control:
    # [...]

    def get_event(self, event):
        clock.tick(20)

    def get_keys(self):
        keys = pg.key.get_pressed()

        if keys[pg.K_LEFT] or keys[pg.K_a]:
            self.trainer.x -= self.trainer.v
        elif keys[pg.K_RIGHT] or keys[pg.K_d]:
            self.trainer.x += self.trainer.v
        elif keys[pg.K_UP] or keys[pg.K_w]:
            self.trainer.y -= self.trainer.v
        elif keys[pg.K_DOWN] or keys[pg.K_s]:
            self.trainer.y += self.trainer.v
Answered By: Rabbid76
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.