eukoloko
eukoloko

Reputation: 201

Pygame: How do I get KEYDOWN to input only once?

Hi I'm creating a game where I have multiple stages. I want to make it so that every time the user presses the key a, the next stage will trigger. Here is a sample of my code.

gameStage = 0 ## outside while loop

##INSIDE whileloop
if gameStage == 0:
    ##insert drawings,music, etc
    if event.type == pygame.KEYDOWN:
       if event.key == pygame.K_a:
            gameStage += 1

if gameStage == 1:
    ##insert drawings,music, etc
    if event.type == pygame.KEYDOWN:
       if event.key == pygame.K_a:
            gameStage += 1

my problem is that when the user presses the a key, a will be input more than once depending how long the key is held. Therefore, it will just skip all the way to my last stage. How do I make it so that the gameStage is +=1 only when the key has been pressed AND lifted? Please tell me if I'm being unclear. Appreciate any help. Thanks.

Upvotes: 7

Views: 18068

Answers (3)

Paul Rooney
Paul Rooney

Reputation: 21609

You could use the pygame.KEYUP event.

e.g.

if event.type == pygame.KEYUP:

But you should not be getting repeated KEYDOWN messages, unless you have called pygame.key.set_repeat and set a non zero repeat value.

The fact that you get the repeated increments of GameStage even when you capture only KEYUP messages would indicate that there is some other issue in your code.

Upvotes: 2

elegent
elegent

Reputation: 4007

When keyboard buttons are pressed or released a pygame.KEDOWN or pygame.KEYUP event appears only ones on the event queue1

As you did, you need to set a global variable GameStage, which indicates the current game state:

GameStage = 0 ## outside while loop

After this we run our main game loop and fetch all events form the even queue using the pygame.event.get() function, which reads and removes events from the queue:

while True:
    #get all events from the  event queue
    for ev in pygame.event.get():

If the read event represents a key-down-event of a the program logic updates the GameStage variable, similar to a so-called state-machine:

if ev.type == pygame.KEYDOWN:
    if ev.key == pygame.K_a:            
        if GameStage == 0:
            GameStage += 1
            #do something

        elif GameStage == 1:
            GameStage += 1
            #do something great

        # and so on ;)

The complete program block looks like this:

#global variable GameStage for state-machine
GameStage = 0 

#main game loop
while True:
    #get all events from the  event queue
    for ev in pygame.event.get():
        if ev.type == pygame.KEYDOWN:
            if ev.key == pygame.K_a:            
                if GameStage == 0:
                    GameStage += 1
                    #do something 

                elif GameStage == 1:
                    GameStage += 1
                    #do something great

                elif GameStage == 2:
                    GameStage += 1
                    #do something great again

                elif GameStage == 3:
                    #this is the last stage, so you cloud go back to stage #0
                    GameStage = 0

                #for debugging print current GameStage 
                print(GameStage)

Only when you press -- no matter how long you hold down -- a the GameStage will be updated only once.

Hope this helps :)

1 As @sloth noted, this can be changed be calling pygame.key.set_repeat(), which will generate multiple pygame.KEYDOWN events when keys are held down.

Upvotes: 1

Synedraacus
Synedraacus

Reputation: 1045

You can either use key up event, as suggested above, or stop reacting to keydown event for a few ticks after it was issued.

Upvotes: 0

Related Questions