How to efficiently hold a key in Pygame?

前端 未结 7 1693
谎友^
谎友^ 2020-12-11 07:10

I\'ve found two related questions:

  • Pygame hold key down causes an infinite loop
  • pygame - on hold button down

But I want to be specific. H

相关标签:
7条回答
  • 2020-12-11 07:20

    I am using a different approach on holding down a key that I am using in the specific task of moving an object left or right.

    I do not care about the computer knowing that a key is actually held down.

    When I press a key, a variable that I define for that key (EG: left arrow) is set to True. Until that key is unpressed (with the event pygame.KEYUP) the "movement to left" is performed.

    0 讨论(0)
  • 2020-12-11 07:27

    You can get keydown event repeatedly if you use pygame.key.set_repeat(# millisecond) to set the time limitation for each key event. Quote: when the keyboard repeat is enabled, keys that are held down will generate multiple pygame.KEYDOWN events. The delay is the number of milliseconds before the first repeated pygame.KEYDOWN will be sent. After that another pygame.KEYDOWN will be sent every interval milliseconds. If no arguments are passed the key repeat is disabled. When pygame is initialized the key repeat is disabled. please see following link for detail http://www.pygame.org/docs/ref/key.html#pygame.key.set_repeat

    0 讨论(0)
  • 2020-12-11 07:29

    This is basically How I did it, well Go to www.cswonders.com, and it might help you . Go to level 3, then 3.6, and go through the tutorial. I learned it from there. Here is my code.

    def update(self):
        self.speedx = 0
        self.speedy = 0
        # If left or right key is pressed, move left or right
        pressed_key = pygame.key.get_pressed()
        if pressed_key[pygame.K_LEFT]: 
            self.speedx = -10          
        if pressed_key[pygame.K_RIGHT]:
            self.speedx = 10
        if pressed_key[pygame.K_UP]:
            self.speedy = -10
        if pressed_key[pygame.K_DOWN]:
            self.speedy = 10
    
        self.rect.x += self.speedx
        self.rect.y += self.speedy
    
        # No further move if off screen
        if self.rect.right > SCREEN_WIDTH:
            self.rect.right = SCREEN_WIDTH
        if self.rect.left < 0:
            self.rect.left = 0
    
    0 讨论(0)
  • 2020-12-11 07:30

    Dominik's solution is the perfect one (separating event.get() from the keyboard ones). It works perfectly! Finally, no more problems with pygame's input.

    Flags:

    flag = False # The flag is essential.
    while not done:
        for e in event.get(): # At each frame it loops through all possible events.
            keys = key.get_pressed() # It gets the states of all keyboard keys.
            if e.type == QUIT:
                done = True
            if e.type == KEYDOWN: # If the type is KEYDOWN (DIFFERENT FROM "HELD").
                if keys[K_DOWN]: # And if the key is K_DOWN:
                    flag = True # The flag is set to true.
            elif e.type == KEYUP: # The very opposite.
                if keys[K_DOWN]:
                    flag = False
        if flag == True: # DON'T USE "while flag == true", it'll crash everything. At every frame, it'll check if the flag is true up there. It's important to remember that the KEYDOWN worked ONLY ONCE, and it was enough to set that flag. So, at every frame, THE FLAG is checked, NOT THE KEYDOWN STATE. Every "player movement" while a key is being held MUST be done through flags.
            print "DOWN"
    
    0 讨论(0)
  • 2020-12-11 07:35

    I like to take a slightly different approach to this problem. Instead of checking if the key is pressed and taking some action when it is, set a flag on key down and unset it on key up. Then in the function to update the player's position, check the flag and update accordingly. The following pseudo-Python explains what I'm getting at:

    if down_key_pressed:
        down_flag = True
    elif down_key_released:
        down_flag = False
    elif right_key_pressed:
        etc...
    

    This should be done in a separate loop that takes the player's input. Then in update_player_position() you can do:

    if down_flag:
        move_player_down()
    elif right_flag:
        move_player_right()
    

    This example assumes four-directional movement, but you could extend it to eight-directional fairly easily by just using if down_flag and right_flag instead.

    0 讨论(0)
  • 2020-12-11 07:43

    I am not familiar with Pygame, but, as I see, the program in it should have an event-based architecture. Unless you get the incoming events and process them, nothing happens. That's why your simple loop becomes infinite: it just does not process events.

    while keys[K_DOWN]: # Nobody updates the keys, no events are processed
        print "DOWN"
    

    Then concerning the get_pressed() call. What it returns is a list of keys. So, you are trying to just loop until the key is released. That's a problem. According to this, pygame.event.get() returns immediately even if there are no events in the queue. The call to get() means: my code still has what to do, but I don't want to block the events, so please process the pending events before I continue. If your code is just waiting for an event, that means it has nothing to do.

    The function to WAIT (without blocking the inner loop of Pygame) for an event is pygame.event.wait() (the logic is: I have nothing to do in my code until something happens). However, if you use it, you will have to get information about keys pressed or released from the event itself, not from get_pressed().

    Here is an example from the comments to the doc page:

    for event in pygame.event.get() :
      if event.type == pygame.KEYDOWN :
        if event.key == pygame.K_SPACE :
          print "Space bar pressed down." #Here you should put you program in the mode associated with the pressed SPACE key
        elif event.key == pygame.K_ESCAPE :
          print "Escape key pressed down."
      elif event.type == pygame.KEYUP :
        if event.key == pygame.K_SPACE :
          print "Space bar released."
        elif event.key == pygame.K_ESCAPE :
          print "Escape key released." #Time to change the mode again
    
    0 讨论(0)
提交回复
热议问题