1

I am coding a game in Python / Pygame. Currently I am working on player movement but I have realised that if I hold the space bar(i.e The button to activate my jump movement) it keeps going up and never comes down. I have implemented gravity but it only takes place when I press the button once. I want this to be so that I can only jump once and my character doesnt keep flying. Here's my code (Please Help!)

# This is my player file
import pygame

class Player(pygame.sprite.Sprite):
    def __init__(self, pos):
        super().__init__()
        self.image = pygame.Surface((32,64))
        self.image.fill('red')
        self.rect = self.image.get_rect(topleft = pos)

    # Player Movement

    self.direction = pygame.math.Vector2(0, 0)
    self.speed = 7
    self.gravity = 0.7
    self.jump_speed = -14

    # player status
    self.status = 'idle'
    self.facing_right = True
    self.on_ground = False
    self.on_ceiling = False
    self.on_left = False
    self.on_right = False

# Key Pressed

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

    if keys[pygame.K_RIGHT]:
        self.direction.x = 1
    elif keys[pygame.K_LEFT]:
        self.direction.x = -1
    else:
        self.direction.x = 0

    if keys[pygame.K_SPACE]:
        self.jump() 
    

# Gravity       

def apply_gravity(self):
        self.direction.y += self.gravity
        self.rect.y += self.direction.y 

# Jumping

def jump(self):
    self.direction.y = self.jump_speed          

# Updating The Player       

def update(self):
    self.get_input()
    self.apply_gravity()

3 Answers3

0

The best way to handle single key presses is to use pygame's event module. Using pygame.event.get() in the main game loop.

That allows you to do something with single 'events' like a key being pressed, or released.

Optionally, you could work around this by adding a space_is_pressed variable that tracks if space was pressed (is set to True when pressed and set back to False when released). Then only trigger something when keys[pygame.K_SPACE] is True, but space_is_pressed is False. I only suggest you do this if you somehow cannot implement pygame.event.get() method.

Andre
  • 760
  • 3
  • 13
0

First of all why do you not only allow to jump if self.on_ground?

class Player(pygame.sprite.Sprite):
    # [...]

    def get_input(self):
        # [...]

        if keys[pygame.K_SPACE] and self.on_ground:
            self.jump() 

Anyway, you have to use the KEYDOWN event instead of pygame.key.get_pressed()

pygame.key.get_pressed() returns a list 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 or a step-by-step movement.

class Player(pygame.sprite.Sprite):
    # [...]

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

        for event in event_list:
            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                self.jump() 
# application loop
while run:

    #event loop
    event_list = pgame.event.get()
    for event in event_list:
        if event.type == pygame.QUIT:
            run = False
  
    # [...]

Note, pygame.event.get() get all the messages and remove them from the queue. See the documentation:

This will get all the messages and remove them from the queue. [...]

If pygame.event.get() is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.

See Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?.


Alternatively you can prevent multiple jumps in a row with a state attribute:

class Player(pygame.sprite.Sprite):
    def __init__(self, pos):
        # [...]
        self.is_jumping = False

    def get_input(self):

        keys = pygame.key.get_pressed()
        if keys[pygame.K_RIGHT]:
            self.direction.x = 1
        elif keys[pygame.K_LEFT]:
            self.direction.x = -1
        else:
            self.direction.x = 0

        space_pressed = keys[pygame.K_SPACE]:
        if space_pressed and not self.is_jumping:
            self.jump() 
        self.is_jumping = space_pressed
       
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
0

The event 'key pressed' is true as long as the key is pressed. Whereas with 'key down' the event only occurs while the key is going down. Wouldn't this be the solution to the problem?