Throttle keypresses in pygame - python

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.

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?

Related

Pygame player can jump for as long as it wants [duplicate]

This question already has answers here:
How to do a variable jump height based on how long key is held in Pygame
(1 answer)
How to make a character jump in Pygame?
(1 answer)
Closed last year.
I'm trying to make a jumping method for my player in pygame. It goes up but I can just hold the space bar key down and it will go up for as long as I want and I don't know how to prevent it. Here's the code for my player class:
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((32, 64))
self.image.fill('blue')
self.rect = self.image.get_rect(topleft = pos)
self.direction = pygame.math.Vector2(0, 0)
self.speed = 8
self.jump_speed = -16
self.gravity = 0.8
def get_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.direction.x = 1
elif keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.direction.x = -1
else:
self.direction.x = 0
if keys[pygame.K_SPACE] or keys[pygame.K_w] or keys[pygame.K_UP]:
self.jump()
def apply_gravity(self):
self.direction.y += self.gravity
self.rect.y += self.direction.y
def jump(self):
self.direction.y = self.jump_speed
def update(self):
self.get_input()
The jump event changes the way the player is moving. When a key is released, then that speed is not reverted. Use the pygame keydown event, and then the keyup event.
import pygame
from pygame.locals import *
#Your code
while True:
#Your event loop code
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_SPACE:
player.jump()
if event.type == KEYUP:
if event.key == K_SPACE:
player.revert_jump()
if event.type == QUIT:
pygame.quit()
exit()

How can you disable key press and hold in pygame? [duplicate]

This question already has answers here:
What all things happens inside pygame when I press a key? When to use pygame.event==KEYDOWN
(1 answer)
How to get keyboard input in pygame?
(11 answers)
Closed 2 years ago.
I am struggling how I can make it so that when a key is pressed in Pygame, you aren't able to keep on holding the key.
I am working on player jumps, but it doesn't work unless the key is only pressed once.
Here is my keypress code:
keys = pygame.key.get_pressed()
if keys[pygame.K_UP] and not self.jumping:
self.jumping = True
And here is my jumping method (which also includes gravity)
def gravity(self):
# if the player isn't jumping
if not self.jumping:
# set acceleration constant and accelerate
self.accel_y = PLAYER_ACCELERATION
self.y_change += self.accel_y
# terminal velocity
if abs(self.y_change) >= PLAYER_MAX_SPEED_Y:
# set the y change to the max speed
self.y_change = PLAYER_MAX_SPEED_Y
self.y += self.y_change
else: # jumping
self.accel_y = -PLAYER_ACCELERATION_JUMPING
self.y_change += self.accel_y
if abs(self.y_change) >= PLAYER_MAX_SPEED_JUMPING:
self.jumping = False
self.y += self.y_change
print(self.y_change)
The player can just keep on holding the up arrow key, and the player will fly - which is not good. I would like it so that you can only press once, and then self.jumping is set to False when it has reached it's top speed (which I have already implemented)
Don't use pygame.key.get_pressed() in this case, but use the keyboard events (see pygame.event).
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 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.
For instance:
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and not self.jumping:
self.jumping = True

Pygame Keys Activating in Multiple Frames [duplicate]

This question already has answers here:
How to get keyboard input in pygame?
(11 answers)
What all things happens inside pygame when I press a key? When to use pygame.event==KEYDOWN
(1 answer)
Python PyGame press two buttons at the same time
(2 answers)
Closed 2 years ago.
In This program I want to have it register Pressed Keys But only once instead of multiple times. If you've played 2048, I am trying to make something like that.
I want to do this without slowing the Frame rate.
import pygame, sys
pygame.init()
WIDTH, HEIGHT = 450,450
win = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
class Tile:
def __init__(self, x, y):
self.x = x
self.y = y
def Move(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
print("Left")
elif keys[pygame.K_RIGHT]:
print("Right")
elif keys[pygame.K_UP]:
print("Up")
elif keys[pygame.K_DOWN]:
print("Down")
keys = pygame.key.get_pressed()
running = run = True
a = Tile(200, 500)
while run:
a.Move()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
sys.exit()
pygame.display.update()
You have to use the key events, rather then 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 movement.
Get the list of events (event_list) in the main application loop and pass the list to the method Move of the class Tile. Handel the events in the method:
import pygame, sys
pygame.init()
WIDTH, HEIGHT = 450,450
win = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
class Tile:
def __init__(self, x, y):
self.x = x
self.y = y
def Move(self, event_list):
for event in event_list:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("Left")
elif event.key == pygame.K_RIGHT:
print("Right")
elif event.key == pygame.K_UP:
print("Up")
elif event.key == pygame.K_DOWN:
print("Down")
running = run = True
a = Tile(200, 500)
while run:
event_list = pygame.event.get()
a.Move(event_list)
clock.tick(60)
for event in event_list:
if event.type == pygame.QUIT:
run = False
sys.exit()
pygame.display.update()

keep holding a key and release a other [duplicate]

This question already has answers here:
Pygame: key.get_pressed() does not coincide with the event queue
(4 answers)
Closed 3 years ago.
i'm actually creating my first game with pygame, but i encounter an issue :
When i'm holding 2 button, everything work perfectly , but as soon as i release one of them , pygame.event.get() return a empty list even if i keep holding the other one.
Because of that issue , my character can't jump forward.
thx for help !
Using python Windows 10 and pygame 1.9.6
in the "character" class :
def move_right(self):
self.speedx += 3
self.sprite = "stand_r"
def move_left(self):
self.speedx -= 3
self.sprite = "stand_l"
def speed_effect(self):
self.posx += self.speedx
self.posy -= self.speedy
#speed limitation :
if self.speedx > 10 :
self.speedx = 10
if self.speedx < -10 :
self.speedx = -10
before main loop :
pygame.key.set_repeat(100,30)
pygame.time.Clock().tick(30)
in the main loop :
for event in pygame.event.get():
keys = pygame.key.get_pressed()
if event.type == QUIT:
continuer = 0
if event.type == KEYDOWN:
if keys[pygame.K_d] or event.key == K_d:
character.move_right()
if keys[pygame.K_a] or event.key == K_a:
character.move_left()
#jump
if character.grounded :
if keys[pygame.K_SPACE]:
character.speedy = 30
pygame.event.get() return a empty list after releasing one button.
The event loop is only executed, when an event occurs. An event occurs at the moment when a button is pressed and a 2nd time when the button is released. When the button is hold no event happens, and the event loop is not executed.
The movement of the mouse would be an event which causes the event loop to be executed.
Use pygame.key.get_pressed() in the main loop (outside the event loop), to get the state of the keys at any time and to perform the movement of the character. The states which are given by pygame.key.get_pressed() are synchronized when pygame.event.get() is called.
for event in pygame.event.get():
keys = pygame.key.get_pressed()
if event.type == QUIT:
continuer = 0
if event.type == KEYDOWN:
if character.grounded :
if event.key == pygame.K_SPACE:
character.speedy = 30
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
character.move_right()
if keys[pygame.K_a]:
character.move_left()

How to make character move when holding down key in Pygame?

Right now, I have this:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
keys = pygame.key.get_pressed()
# moves hero with key presses
if keys[pygame.K_LEFT] == 1:
hero.goLeft()
if keys[pygame.K_RIGHT] == 1:
hero.goRight()
elif keys[pygame.K_UP] == 1:
hero.goUp()
elif keys[pygame.K_DOWN] == 1:
hero.goDown()
However, I'm still having to press the key multiple times to move the character. Does anyone know why or have a different solution?
Thanks!
keys = pygame.keys.get_pressed() and the following lines should not be inside of the event loop, otherwise it's called only once for each event that gets added to the event queue and you won't get continuous movement. Just dedent these lines.
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
keys = pygame.key.get_pressed()
# moves hero with key presses
if keys[pygame.K_LEFT]:
hero.goLeft()
elif keys[pygame.K_RIGHT]:
hero.goRight()
if keys[pygame.K_UP]:
hero.goUp()
elif keys[pygame.K_DOWN]:
hero.goDown()
You can also just check if keys[pygame.K_LEFT]: instead of if keys[pygame.K_LEFT] == 1:.

Categories