2
\$\begingroup\$

I am new to creating games with graphics, and I want to make a very hard game. I have the movement down, but it has a weird bug where it if the user presses down the opposing movement key (i.e. A is to go left and D is to go right), it goes in the opposite direction and when the user stops pressing the opposing key in question, they stop moving in either direction.

I have did research to try to solve this problem myself, and found this question on Stack Overflow, and it made sense, but when I tried it, just made it even worse.

How can I stop the player from moving if the opposing key is pressed at the same time?

Code

Original Code

while True:
    if player.canMove:
                if e.type == KEYDOWN:
                    if pressed[K_w] and not pressed[K_s]:
                        dy = -player.speed
                    if pressed[K_a] and not pressed[K_d]:
                        dx = -player.speed
                    if pressed[K_s] and not pressed[K_w]:
                        dy = player.speed
                    if pressed[K_d] and not pressed[K_a]:
                        dx = player.speed
                elif e.type == KEYUP:
                    if e.key == K_c or e.type == QUIT:
                        close()
                    if e.key == K_a:
                        dx = 0
                    elif e.key == K_d:
                        dx = 0
                    elif e.key == K_w:
                        dy = 0
                    elif e.key == K_s:
                        dy = 0

Modified Code

while True:

    up = None
    left = None
    down = None
    right = None

    if player.canMove:
                if e.type == KEYDOWN:
                    up = pressed[K_w]
                    left = pressed[K_a]
                    down = pressed[K_s]
                    right = pressed[K_d]

                    dx += (right - left) * player.speed
                    dy += (down - up) * player.speed
                elif e.type == KEYUP:
                    if e.key == K_c or e.type == QUIT:
                        close()
                    if e.key == K_a:
                        dx = 0
                    elif e.key == K_d:
                        dx = 0
                    elif e.key == K_w:
                        dy = 0
                    elif e.key == K_s:
                        dy = 0
```
\$\endgroup\$
4
  • \$\begingroup\$ Is there a particular reason you're leaving the movement variables set for multiple frames? That approach means you have a state that you need to factor into subsequent key presses. If you were to switch to checking the state of the keys (is pressed, rather than up/down) then the logic becomes stateless [If A and not D ..., If D a and not A, etc...] \$\endgroup\$
    – Basic
    Feb 23 at 18:42
  • \$\begingroup\$ I have tried that, and it doesn't do anything. \$\endgroup\$
    – Tiimzee
    Feb 23 at 18:45
  • 1
    \$\begingroup\$ Am I correct in understanding that up = pressed[K_w] is equivalent to your linked question's answer of pressed[pygame.K_w]? \$\endgroup\$ Feb 24 at 9:53
  • 1
    \$\begingroup\$ Yes, that is correct. \$\endgroup\$
    – Tiimzee
    Feb 26 at 17:48

2 Answers 2

1
\$\begingroup\$

The simplest option would simply be to change your "else" condition to subtract instead of setting to zero....

            elif e.type == KEYUP:
                if e.key == K_c or e.type == QUIT:
                    close()
                if e.key == K_a:
                    dx += player.speed
                elif e.key == K_d:
                    dx -= player.speed
                elif e.key == K_w:
                    dy += player.speed
                elif e.key == K_s:
                    dy -= player.speed

That way, moving both ways cancels out and when one key is released you get the correct movement again.

\$\endgroup\$
1
\$\begingroup\$

Depending on how you're interpreting dx/dy from between frames, you may want to skip the dx/dy += statements

Focusing on this code block:

if e.type == KEYDOWN:
                    up = pressed[K_w]
                    left = pressed[K_a]
                    down = pressed[K_s]
                    right = pressed[K_d]

                    dx += (right - left) * player.speed
                    dy += (down - up) * player.speed

It looks like you're usually just increasing dx and dy every time a key is down, but with the key's information about which key is pressed, you can check against if a past key was pressed and you're processing one key being lifted up while still processing the keydown for another key.

For example:

If you're pressing down the "w" key, and then you press down the "S" key at the same time that you lift up the "w" key, it's possible that you're "Skipping" the event of registering that "W" got lifted, and "S" is being registered as being placed down.

One way to make this more robust is to check if dx or dy are positive or negative, and compare that to the opposing key.

If you turned the above into:

if e.type == KEYDOWN:
                    up = pressed[K_w]
                    left = pressed[K_a]
                    down = pressed[K_s]
                    right = pressed[K_d]

                    if (not (left and (dx >= 0))) and (not (right and (dx <= 0))):
                        # If we get here, we're not holding the "A" key down when we went right in a previous frame, or the "D" key when we're going left in a previous frame.
                        dx += (right - left) * player.speed
                    else:
                        dx = 0
                    if (not (up and (dy >= 0))) and (not (down and (dy >= 0))):
                        # If we get here, we're not holding the "W" key down when we went down in a previous frame, or the "S" key when we're going up in a previous frame.
                        dy += (down - up) * player.speed
                    else:
                        dy = 0
                    # ...etc.

The above presumes that you want dx and dy to be accelerating every while loop where the key in the same direction is pressed, and not the opposite direction key being pressed (As dx and dy are being added to, not assigned to the movement value of (right -left) * player.speed - that might mean that the value could be kept constant instead of zeroing it out otherwise, and by removing the else statements, you can keep their momentum going until they drop the key they were holding and they then get to the "Key up" event and get zeroed out there as well.

As a note:

I suspect that the reason the linked code didn't work here, is that lines like dx += (right - left) * player.speed are about changing the delta to the player.x value, not the player.x value being added to itself (That is, after calculating dx here, you later went to player.x += dx.). So when (right-left) * player.speed was negative, but dx was already positive, you were decelerating by player.speed delta in the opposite direction - and every frame it was accelerating the deceleration. This might be the case if you were seeing the player character slow down moving in the positive direction once the opposing key is pressed, then and speed up in the negative direction. It may have been that dx was 0 for a single frame, and then the next frame immediately applied the reversed dx value.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .