Is there a better way to move the sprite using the keyboard with Pygame?

I currently have a small image that I move using the D and A keys on my keyboard. The code works exactly the way I want it to, but it seems to be a little overcomplicated. Is there a more efficient way to do this?

In the main loop, my code checks which key is pressed through events, but after that, if the key is no longer pressed, it checks to see if another key is pressed, just in case the user pressed another key first.

Here is my code:

import pygame
import sys
from pygame.locals import *

SCREENX = 640
SCREENY = 480

LEFT = 'left'
RIGHT = 'right'


class Character(pygame.sprite.Sprite):
    def __init__(self, image_file):
        super().__init__()
        temp_image = pygame.image.load(image_file)
        self.image = pygame.transform.scale(temp_image, (100, 100))
        self.rect = self.image.get_rect()
        self.moving = False
        self.direction = RIGHT

    def start_move(self, direction):
        self.moving = True
        if direction != self.direction:
            self.image = pygame.transform.flip(self.image, True, False)
        self.direction = direction

    def stop_move(self):
        if self.moving:
            self.moving = False

    def move(self):
        if self.direction == RIGHT:
            self.rect.x += 5
        if self.direction == LEFT:
            self.rect.x -= 5

    def update(self):
        if self.moving:
            self.move()


def main():
    pygame.init()
    surface = pygame.display.set_mode((SCREENX, SCREENY))
    clock = pygame.time.Clock()

    sprites = pygame.sprite.Group()

    girl = Character("assets/girl.png")
    girl.rect.x = SCREENX/2
    girl.rect.y = SCREENY - girl.rect.height

    sprites.add(girl)

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN:
                if not girl.moving:
                    if event.key == K_d:
                        girl.start_move(RIGHT)
                    if event.key == K_a:
                        girl.start_move(LEFT)
            if event.type == KEYUP:
                if event.key == K_a or event.key == K_d:
                    girl.stop_move()
                    keys_pressed = pygame.key.get_pressed()
                    if keys_pressed[K_d]:
                        girl.start_move(RIGHT)
                    if keys_pressed[K_a]:
                        girl.start_move(LEFT)

        surface.fill((255, 255, 255))
        sprites.update()
        sprites.draw(surface)
        pygame.display.update()
        clock.tick(60)


if __name__ == '__main__':
    main()

      

+3


source to share


1 answer


Yes, you can get rid of most of the event handling, you can generalize your main loop and get rid of some of the fields in your class Character

.

See my explanatory notes in the comments:



import pygame
import sys
from pygame.locals import *

SCREENX = 640
SCREENY = 480


class Character(pygame.sprite.Sprite):
    def __init__(self, image_file):
        pygame.sprite.Sprite.__init__(self)
        temp_image = pygame.image.load(image_file)
        # only to the flipping of the image once
        self.image_r = pygame.transform.scale(temp_image, (100, 100))
        self.image_l = pygame.transform.flip(self.image_r, True, False)
        self.image = self.image_l
        self.rect = self.image.get_rect()

    def update(self, pressed_keys):
        move = 0
        if pressed_keys[K_d]: move += 1
        if pressed_keys[K_a]: move -= 1
        self.rect.move_ip(move*5, 0)

        # check which direction we're facing and set the image
        self.image = self.image_l if move < 0 else self.image_r

def main():
    pygame.init()
    surface = pygame.display.set_mode((SCREENX, SCREENY))
    clock = pygame.time.Clock()

    sprites = pygame.sprite.Group()

    girl = Character("assets/girl.png")
    girl.rect.x = SCREENX / 2
    girl.rect.y = SCREENY - girl.rect.height

    sprites.add(girl)

    while True:
        for event in pygame.event.get():
            # since we are in a function, we can simply return.
            # we don't care here what happens after we quit the main loop
            if event.type == QUIT: return pygame.quit()

        # get all pressed keys, and just let all sprites 
        # decide what they want to do with it
        keys_pressed = pygame.key.get_pressed()

        # you could wrap this information in a more
        # general container represeting the game state
        # See how the game loop does not care what a 
        # Sprite does with this information
        sprites.update(keys_pressed)

        surface.fill((255, 255, 255))
        sprites.draw(surface)
        pygame.display.update()
        clock.tick(60)


if __name__ == '__main__':
    main()

      

+2


source







All Articles