problem with continuous motion using pygame - python

I'm trying to get my character to move as long as the key is pressed but so far it moves once per single press and the key needs to be released for him to move again.
I've tried using the pygame.key.get_pressed() as shown and I can't figure out what's wrong with it.
def keyPressed(input_key):
keysPressed = pygame.key.get_pressed()
if keysPressed[input_key]:
return True
else:
return False
...
run = True
while run:
for event in pygame.event.get():
if keyPressed(pygame.K_LEFT) and x > vel:
x -= vel
...

You have to call pygame.key.get_pressed() in the application loop rather than the main loop. The event loop is only executed when an event occurs (like pygame.KEYDOWN). But the application loop is executed in every frame.
The typical use for pygame.key.get_pressed() may look as follows:
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#<---| Indentation
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel:
x -= vel
if keys[pygame.K_RIGHT] and x < width-vel:
x += vel
# [...]

Related

Throttle keypresses in pygame

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?

pygame - while loop makes pygame window freeze / how do I shoot the bullets out of the player?

so I was programming again this morning and I wanted to write that the player in my small game can shoot bullets. That worked fine but theres an issue: I wrote for the x and the y coordinates of the 'bullet spawner' player.x and player.y and I thought that the bullets would shoot from the player's position. but they don't. They shoot from the position, where the player was in the beginning of the game and the spawner doesn't move. So I tried to do this with a while loop and the bool isMoving, that only is True if the player moves:
...
isMoving = False
...
bullets = []
position = (player.x, player.y)
while isMoving:
position = (player.x, player.y)
...
if keys[pygame.K_d] or keys[pygame.K_a] or keys[pygame.K_w] or keys[pygame.K_s] or keys[pygame.K_UP] or keys[pygame.K_DOWN] or keys[pygame.K_LEFT] or keys[pygame.K_RIGHT]:
isMoving = True
else:
isMoving = False
But if I run pygame now, the window just freezes. If I remove the while loop again, it works but it shoots from the player's first position again.
Oh, and I get the error " while isMoving:
UnboundLocalError: local variable 'isMoving' referenced before assignment
" Any ideas how to fix that?
Pygame should run in a main while loop which has all the main actions inside it.
Try setting the position at the start, then inside the while loop check for pygame events that trigger the isMoving change. Nested while loops will cause issues with pygame. Use if functions inside the while loop instead of another while loop. For example,
position = (player.x, player.y) # initial position
while isRunning:
isMoving = False
# PyGame event interaction
for event in pygame.event.get():
# Exits loop
if event.type == pygame.QUIT:
isRunning = False
# Check if key is pressed
if event.type == pygame.KEYDOWN:
keys = [pygame.K_a, pygame.K_w, pygame.K_s, pygame.K_d, pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT]
if event.key in keys:
isMoving = True
if isMoving:
position = (player.x, player.y)
# do other stuff

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()

Creating borders while using pygame.key.get_pressed()

I am coding a top-down shooter game, and was recently trying to figure out a way to continuously move my character while holding down a key. I was searching the internet to find a way, and found pygame.key.get_pressed(), this worked great until I tried to create borders so you couldn't escape the sides of the screen. I have basically worked out the problem being while your holding down the movement keys, pygame can't check the x and y coordinates of your player, therefore it allows the player to move out of bounds even when you add something like if x >= 0:.
I am asking if there is a way to create a border for the sides of the screen, while holding down a movement button with pygame.key.get_pressed(), or if there is a good alternative for moving.
Some of the code :
if eventHandler == "LEVEL1":
# SEE IF PLAYER QUIT AND PROCEED TO QUIT
for event in pygame.event.get():
if event.type == pygame.QUIT:
loop = False
if event.type == pygame.KEYDOWN:
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
movingUP = True
if keys[pygame.K_DOWN]:
movingDOWN = True
if keys[pygame.K_LEFT]:
movingLEFT = True
if keys[pygame.K_RIGHT]:
movingRIGHT = True
if event.type == pygame.KEYUP:
movingUP = False
movingDOWN = False
movingLEFT = False
movingRIGHT = False
x_change = 0
y_change = 0
if movingUP == True:
y_change -= 5
if movingDOWN == True:
y_change += 5
if movingLEFT == True:
x_change -= 5
if movingRIGHT == True:
x_change += 5
# UPDATES EVERY TIME GAME LOOPS
pygame.display.update()
clock.tick(60)
x += x_change
y += y_change
if eventHandler == "LEVEL1":
w.blit(level1map, (0, 0))
w.blit(player, (x, y))
pygame.display.update()
I have already tried adding (with 16 being the border)
if x >= 16:
x_change = 0
movingLEFT = 0
and so on with all of the directions. I tried this for basically anywhere it would make sense in the code. I have also tried putting
if keys[pygame.K_LEFT] and x >= 16:
movingLEFT = True
"and variable >= border" everywhere it might make a border, but still no results.
Any way to create a border that works or an alternative for moving?
[...] while your holding down the movement keys, pygame can't check the x and y coordinates of your player, [...]
No.
While your holding down the movement keys, no event occurs. There is a single pygame.KEYDOWN event when the key is pressed and a single pygame.KEYUP event when the key is released.
But there are no continuously events, when a key is pressed.
It is perfect suitable to get the pressed key in the event loop by (pygame.key.get_pressed()) and to change the state of the control variables movingUP, movingDOWN, movingLEFT movingRIGHT. The values which are returned by pygame.key.get_pressed() are updated when the event is handled by pygame.event.get().
But the bounds check has to be done in every frame, every time when the position (x, y) was changed. It has to bed done in the main game loop, rather than the event loop:
maxX = # screenWidth - playerWidth
maxY = # screenHeight - playerHeight
while loop:
if eventHandler == "LEVEL1":
# SEE IF PLAYER QUIT AND PROCEED TO QUIT
for event in pygame.event.get():
if event.type == pygame.QUIT:
loop = False
if event.type == pygame.KEYDOWN:
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
movingUP = True
# [...]
if movingUP == True:
y_change -= 5
# [...]
x += x_change
y += y_change
if x < 0:
x = 0
x_change = 0
elif x > maxX
x = maxX
x_change = 0
if y < 0:
y = 0
y_change = 0
elif y > maxY
y = maxY
y_change = 0

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