1

I was recently coding a platformer game, when I faced into a problem: The user could spam space to jump infinitely.

Here is my code:

def __init__(self, pos):
    super().__init__()
    self.image = pygame.Surface((32, 64))
    self.image.fill("green")
    self.rect = self.image.get_rect(topleft = pos)
    self.direction = pygame.math.Vector2(0, 0)
    self.speed = speed
    self.gravity = gravity
    self.jump_height = jump_height

def get_input(self):
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and keys[pygame.K_RIGHT]: pass
    elif keys[pygame.K_LEFT]: self.direction.x = -1
    elif keys[pygame.K_RIGHT]: self.direction.x = 1
    else: self.direction.x = 0
    if keys[pygame.K_SPACE]:
        self.jump()

I tried several things, such as implementing a self.antispam boolean, set to True, at the __init__ method that turns into False when the space key is pressed, and then turns True again after the jump method, or turning the jump method into a coroutine to make an asyncio loop, but none of them worked.

Tomalak
  • 332,285
  • 67
  • 532
  • 628

1 Answers1

1

To jump you have to use KEYDOWN instead of pygame.key.get_pressed(). Use pygame.key.get_pressed() to move but not to jump.
pygame.key.get_pressed() returns a sequence with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action like jumping or spawning a bullet.

Make sure you only call pygame.get.event() once (see Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?):

    def get_input(self, event_list):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] and keys[pygame.K_RIGHT]: pass
        elif keys[pygame.K_LEFT]: self.direction.x = -1
        elif keys[pygame.K_RIGHT]: self.direction.x = 1
        else: self.direction.x = 0

        for event in event_list:
            if event.type == pygame.KEYDONW and event.key == pygame.K_SPACE:
                self.jump()
# application loop
while run:
    # event loop
    event_list = pygame.get.event()
    for event in event_list:
        if event.type == pygame.QUIT:
            # [...]

    player.get_input(event_list)

The other option is to state if SPACE was pressed in previous frames. So you can detect that the SPACE is hold down:

def __init__(self, pos):
    super().__init__()
    # [...]
   
    self.space_was_pressed = False

def get_input(self):
    keys = pygame.key.get_pressed()
    # [...]         

    space_is_pressed = keys[pygame.K_SPACE]  
    if space_is_pressed and not self.space_was_pressed:
        self.jump()
    self.space_was_pressed = space_is_pressed 

See also How to make a character jump in Pygame?

Rabbid76
  • 202,892
  • 27
  • 131
  • 174