Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I've been writing a simple top down mini RPG in python.

My problem is that when I move the player I have to repeatedly tap the arrow key. Each time I tap the key the player moves 5 PX in the direction of the key I press, but if I hold down the key he doesn't keep moving, he just moves the first 5 PX.

My moving code looks like this:

# event loop
    for event in pygame.event.get():
        if event.type == pygame.QUIT: 
            sys.exit()        
        elif event.type == pygame.KEYDOWN:          # check for key presses          
            if event.key == pygame.K_LEFT:        # left arrow turns left
                x = x + -x_speed
            elif event.key == pygame.K_RIGHT:     # right arrow turns right
                x = x + x_speed
            elif event.key == pygame.K_UP:        # up arrow goes up
                y = y + -y_speed
            elif event.key == pygame.K_DOWN:     # down arrow goes down
                y = y + y_speed    

And farther up I define the x_speed ect.

How do I make it keep moving when I hold down the key?

share|improve this question
    
You can only get one KEYDOWN event per key press. If you want to hold down a key you need to toggle a boolean. I read below that you couldn't get this to work, but I'm pretty confident that it is the only way you can get the effect you are looking for. –  Benjamin Danger Johnson May 2 '13 at 21:22
add comment

4 Answers 4

I don't know python or pygame, but assuming you're using a game library there should be a way to poll the state of the key, such as if it's currently down or not instead of if it was pressed since last update. Use that for checking and updating movement.

The next problem you will run into is it will update movement as fast as your logic update interval is as long as the key is held down. To fix this you need a variable to act as a cooldown so when you poll the state of the key and use it to move, the variable is set to the cooldown amount, and you can't move again until that cooldown reaches zero. So for an example of basic movement code assuming an arbitrary library and language:

constant int COOLDOWN_TIME = 170; //170 milliseconds
int cooldown = 0;

void update(int delta) {
    if (cooldown <= 0) {
        if (Input.isKeyDown(Key_Left)) {
            x -= x_speed;
            cooldown += COOLDOWN_TIME;
        }
        else if (Input.isKeyDown(Key_Right)) {
            x += x_speed;
            cooldown += COOLDOWN_TIME;
        }
        if (Input.isKeyDown(Key_Up)) {
            y -= y_speed;
            cooldown += COOLDOWN_TIME;
        }
        else if (Input.isKeyDown(Key_Down)) {
            y += y_speed
            cooldown += COOLDOWN_TIME;
        }
    }
    else {
        cooldown -= delta;
    }
}

Where delta would be the time in milliseconds passed since the last logic update.

share|improve this answer
add comment

Your problem is the fact that you're only looking at KEYDOWN events.

What you need to do is toggle a boolean value when a key is pressed or released.

Something like this would work:

# event loop
for event in pygame.event.get():
    if event.type == pygame.QUIT: 
        sys.exit()        
    elif event.type == pygame.KEYDOWN:          # check for key presses          
        if event.key == pygame.K_LEFT:        # left arrow turns left
            pressed_left = True
        elif event.key == pygame.K_RIGHT:     # right arrow turns right
            pressed_right = True
        elif event.key == pygame.K_UP:        # up arrow goes up
            pressed_up = True
        elif event.key == pygame.K_DOWN:     # down arrow goes down
            pressed_down = True
    elif event.type == pygame.KEYUP:            # check for key releases
        if event.key == pygame.K_LEFT:        # left arrow turns left
            pressed_left = False
        elif event.key == pygame.K_RIGHT:     # right arrow turns right
            pressed_right = False
        elif event.key == pygame.K_UP:        # up arrow goes up
            pressed_up = False
        elif event.key == pygame.K_DOWN:     # down arrow goes down
            pressed_down = False

# In your game loop, check for key states:
if pressed_left:
    x -= x_speed
if pressed_right:
    x += x_speed
if pressed_up:
    y -= y_speed
if pressed_down:
    y += y_speed

This way, you're actually looking at both presses and releases, and moving while the key is pressed.

share|improve this answer
    
this didn't work –  Cagentdog May 2 '13 at 15:42
    
Oh bugger, I didn't realize the fact that the state-checking code needs to be in your gameloop. –  Raceimaztion May 2 '13 at 23:08
add comment

I asked a question here that's very similar, and received the following answer:

The way to deal with this is to set a timer once the person taps the phone. The most user friendly scenario that you'd implement would look something like this:

  1. When you detect a tap, set a timer (t = timeToRepeat)

  2. On each frame, decrease the timer by dt

  3. If the timer reaches zero, move the sprite a tile and reset the timer
  4. If the user releases their finger before the first cycle of the timer, move the sprite one tile

Obviously the amount of time that you set your timer to will determine how fast your sprite moves. There are a few variations on this theme depending on the kind of behavior you want as well. For example, you can move the sprite once immediately upon detecting a tap and ignore step #4.

Implementing this would make the user able to tap to move a single time and to be able to move multiple tiles by holding, which I think is ideal.

share|improve this answer
add comment

I don't know python, but have you tried setting a bool to true when the key is pressed, and changing the speed in an if statement based on that bool. When the key gets released you just have to set the bool back to false.

share|improve this answer
    
Ok I'll try that –  Cagentdog May 1 '13 at 18:54
1  
If the API doesn't provide an "is pressed" state for the keys, that is a good solution. –  Cristina May 1 '13 at 18:58
    
I couldn't get this to work. –  Cagentdog May 2 '13 at 15:41
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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