1
\$\begingroup\$

I did the code this way to avoid the player to stop if a press two directional keys together making the movement more smooth. It works well but when I release two keys or more together the player keep moving in one of the directions of the key. I can't figure out how to solve this issue.

Here is my code:

def input(self, event, pygame):
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_LEFT:
            self.left_is_down = True
            self.speed_x = -self.velocity
        if event.key == pygame.K_RIGHT:
            self.right_is_down = True
            self.speed_x = self.velocity
        if event.key == pygame.K_UP:
            self.up_is_down = True
            self.speed_y = -self.velocity
        if event.key == pygame.K_DOWN:
            self.down_is_down = True
            self.speed_y = self.velocity

    if event.type == pygame.KEYUP:
        if event.key == pygame.K_LEFT:
            self.left_is_down = False
            if self.right_is_down:
                self.speed_x = self.velocity
            else:
                self.speed_x = 0
        if event.key == pygame.K_RIGHT:
            self.right_is_down = False
            if self.left_is_down:
                self.speed_x = -self.velocity
            else:
                self.speed_x = 0
        if event.key == pygame.K_UP:
            self.up_is_down = False
            if self.down_is_down:
                self.speed_y = self.velocity
            else:
                self.speed_y = 0
        if event.key == pygame.K_DOWN:
            self.down_is_down = False
            if self.up_is_down:
                self.speed_y = -self.velocity
            else:
                self.speed_y = 0


def update(self):

    self.x += self.speed_x
    self.y += self.speed_y
\$\endgroup\$
2
  • \$\begingroup\$ I'm not familiar with pygame, but this can usually be tackled by not checking if the button was just pressed down or released, but just checking the key's state. That way, you won't miss crazy situations like the keyboard being disconnected. \$\endgroup\$ – Peethor May 10 '16 at 18:12
  • \$\begingroup\$ Thanks, you helped me to figure out a solution. It was realy necessary to check the key state in this case \$\endgroup\$ – Otavio May 12 '16 at 2:18
3
\$\begingroup\$

In pygame (and many other frameworks like it), events are received in an event queue. Multiple events can arrive per frame, for example when you press or release two buttons together. You need to consume the event queue before proceeding. Typically that looks like this:

while True:
    for event in pygame.event.get():
        if event == pygame.KEYDOWN:
            # handle key pressed
        elif event == pygame.KEYUP:
            # handle key released
        # handle other events
    # update
    # render

You haven't shown how your input() is called, but I suspect you're not looping over pygame.event.get(), which explains why some key events are missing.

But a simpler solution for your problem is to forget about key events, and simply get the state of all keys pressed, via pygame.key.get_pressed(), like in your proposed solution, but that's all you need. Leave the KEYDOWN/KEYUP events for when you need to know when a key is first pressed, or released. Then it's just:

while True:
    pressed = pygame.key.get_pressed()
    if pressed[pygame.K_LEFT]:
        # Go left
    if pressed[pygame.K_UP]:
        # Go up
    # Or handle diagonals, like pressed[pygame.K_LEFT] and pressed[pygame.K_UP]
\$\endgroup\$
0
\$\begingroup\$

If you remove the part bellow, maybe it can work. I do this in the JavaScript game and worked, try it:

if event.type == pygame.KEYUP:
    if event.key == pygame.K_LEFT:
        self.left_is_down = False
        if self.right_is_down:
            self.speed_x = self.velocity
        else:
            self.speed_x = 0
    if event.key == pygame.K_RIGHT:
        self.right_is_down = False
        if self.left_is_down:
            self.speed_x = -self.velocity
        else:
            self.speed_x = 0
    if event.key == pygame.K_UP:
        self.up_is_down = False
        if self.down_is_down:
            self.speed_y = self.velocity
        else:
            self.speed_y = 0
    if event.key == pygame.K_DOWN:
        self.down_is_down = False
        if self.up_is_down:
            self.speed_y = -self.velocity
        else:
            self.speed_y = 0
\$\endgroup\$
0
\$\begingroup\$

I'm a beginer in pygame and python so i'm having some troubles hahahahah.

I figured ou what my problem was. Pygame does not reognize two keys being pressed or released at the same time.

So for example, when i press the down button, and the right button the program states that self.down_is_down = True and self.right_is_down = True so the player gain a positive vertical speed and a positive horizontal speed.

But if i release two of then together pygame just recognize one being released so only one of self.down_is_down and self.right_is_down will be set False and the player will keep moving to one of the directions.

to solve this i add in the end if event.type == pygame.KEYUP block the following code:

      if not pygame.key.get_pressed()[pygame.K_LEFT] and not pygame.key.get_pressed()[pygame.K_RIGHT]:
        self.speed_x = 0
        self.left_is_down = False
        self.right_is_down = False
    if not pygame.key.get_pressed()[pygame.K_UP] and not pygame.key.get_pressed()[pygame.K_DOWN]:
        self.speed_y = 0
        self.down_is_down = False
        self.up_is_down = False

wich checks if the keys are still being pressed. I don't think it's the better way to solve that problem but it works for now

\$\endgroup\$
2
  • \$\begingroup\$ I'd better first detect the pressed keys, and then compute the velocity to add. after knowing such states and velocity (as a vector, perhaps) I'd assign the velocity vector to the appropriate variables \$\endgroup\$ – Luis Masuelli Aug 8 '16 at 21:24
  • 1
    \$\begingroup\$ This actually not true. Pygame does recognize if keys is pressed or released simultaneously. Your solution must have fixed another problem with your code. \$\endgroup\$ – Ted Klein Bergman Aug 8 '16 at 21:27
0
\$\begingroup\$

I've tried out a smooth way to move around a player that works pretty well. It basically keeps track of the key presses in a list and moves the player based on the last key pressed. When you press a key it'll add a speed variable at the first position in the list, and when you release the key it'll remove that variable. In the update method you'll add the first speed variable of the list to corresponding x and y value.

import pygame
pygame.init()

screen = pygame.display.set_mode((720, 480))

class Player(pygame.sprite.Sprite):

    def __init__(self):
        super(Player, self).__init__()
        self.rect = pygame.Rect((0, 0), (32, 32))
        self.image = pygame.Surface((32, 32))
        self.image.fill((255, 255, 255))
        self.velocity = [0, 0]  # It's current velocity.
        self.speed = 4  # The speed the player will move.
        self.dx = []  # Keeps track of the horizontal movement.
        self.dy = []  # Keeps track of the vertical movement.

    def update(self):
        try:
            self.rect.x += self.dx[0]  # Index error if the list is empty.
        except IndexError:
            self.rect.x += 0
        try:
            self.rect.y += self.dy[0]  # Index error if the list is empty.
        except IndexError:
            self.rect.y += 0

player = Player()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            raise SystemExit
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                player.dx.insert(0, -player.speed)
            elif event.key == pygame.K_d:
                player.dx.insert(0, player.speed)
            elif event.key == pygame.K_w:
                player.dy.insert(0, -player.speed)
            elif event.key == pygame.K_s:
                player.dy.insert(0, player.speed)
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_a:
                player.dx.remove(-player.speed)
            elif event.key == pygame.K_d:
                player.dx.remove(player.speed)
            elif event.key == pygame.K_w:
                player.dy.remove(-player.speed)
            elif event.key == pygame.K_s:
                player.dy.remove(player.speed)

    player.update()
    screen.fill((0, 0, 0))
    screen.blit(player.image, player.rect)
    pygame.display.update()

    # print player.dx, player.dy  # Uncomment to see what's happening in action!
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.