# How can I make smoother upwards/downwards controls in pygame?

This is a loop I use to interpret key events in a python game.

# Event Loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
my_speed = -10;
if event.key == pygame.K_d:
my_speed = 10;
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
my_speed = 0;
if event.key == pygame.K_d:
my_speed = 0;


The 'A' key represents up, while the 'D' key represents down. I use this loop within a larger drawing loop, that moves the sprite using this:

Paddle1.rect.y += my_speed;


I'm just making a simple pong game (as my first real code/non-gamemaker game) but there's a problem between moving upwards <=> downwards. Essentially, if I hold a button upwards (or downwards), and then press downwards (or upwards), now holding both buttons, the direction will change, which is a good thing. But if I then release the upward button, then the sprite will stop. It won't continue in the direction of my second input.

This kind of key pressing is actually common with WASD users, when changing directions quickly. Few people remember to let go of the first button before pressing the second. But my program doesn't accommodate the habit.

I think I understand the reason, which is that when I let go of my first key, the KEYUP event still triggers, setting the speed to 0. I need to make sure that if a key is released, it only sets the speed to 0 if another key isn't being pressed. But the interpreter will only go through one event at a time, I think, so I can't check if a key has been pressed if it's only interpreting the commands for a released key.

This is my dilemma. I want set the key controls so that a player doesn't have to press one button at a time to move upwards <=> downwards, making it smoother. How can I do that?

What I always use is something like the following:

# somewhere outside the main loop
inputMap = [False, False]

# somewhere inside the main loop
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
inputMap[0] = True;
if event.key == pygame.K_d:
inputMap[1] = True;
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
inputMap[0] = False;
if event.key == pygame.K_d:
inputMap[1] = False;

# recalculate speed based on current input state
my_speed = 0
if inputMap[0]: my_speed -= 10
if inputMap[1]: my_speed += 10


Things become easier when you store the "state" of your input, and recalculate the speed each frame given the current state.

If you're not keen on clearing my_speed every frame, you could tweak it like this:

if inputMap[0]: my_speed = -10
if inputMap[1]: my_speed = 10
if not inputMap[0] and not inputMap[1]: my_speed = 0

• It won't move consistently unless you take inputMap out of the MainLoop, otherwise it works. Thanks! – Zolani13 Nov 11 '12 at 18:12

In pygame you can check the unbuffered key state (not PRESSED/RELEASED events, but whether a key is CURRENTLY pressed) like so:

keys = pygame.key.get_pressed()
my_speed = 0
if keys[pygame.K_a]: my_speed -= 10
if keys[pygame.K_d]: my_speed += 10


Code is not tested, but should work nonetheless. Like this it will block when pressing both buttons (which IMO is what it should do) and move again when you release either of them.

Maybe the easiest way is to write an own class for this:

class buttons():
def __init__(self):
self.Wpressed = False
...
def get_state(self,pygame):
for event in pygame.get_event():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w: self.Wpressed = True
...


Call get_state() every frame and set the moving speed of your sprite:

my_speed = 0
if mybuttons.Wpressed: my_speed = -10
...