Pygame - when i push a button and then another - python

First of all, here is my code:
while not crashed:
curr_event = pygame.event.get()
if (len(curr_event) == 2):
print curr_event[0],'\n',curr_event[1],'\n\n\n'
for event in curr_event:
if event.type == pygame.KEYUP and not len(curr_event) == 1:
continue
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
elif event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
x_change = 0
x += x_change
Display.fill((255, 255, 255))
car(x,y)
pygame.display.update()
clock.tick(100)
This should be a try to move smoothly from right to left and opposite.
All is good when for example, I press "left key" and wait 2 seconds and then press "right key".
But - when I press "left key", leave the key, and just after it press "right key" - the "key up" is smashing my right press and the player stops on the screen.
I thought it's because created a list of 2 indexes when the first have the "right press" and the second have the "key up", so i tried to do:
if event.type == pygame.KEYUP and not len(curr_event) == 1:
continue
As you can see in my code.
Well... sometimes it's the situation... But sometimes it doesn't creates a list with two indexes - but smash the "right key" pressing..
How can I fix it and what is the issue?

Moving the mouse, pressing buttons and other actions counts as events and are put in the queue, so the code if event.type == pygame.KEYUP and not len(curr_event) == 1: continue might be unreliable.
Solution
You could check the state of the button (if it's being held down or not) rather than just when it's pressed and released. pygame.key.get_pressed() returns a list of all the keys current state: 0 if not being pressed and 1 if it's being pressed. A key position in the list is it's integer constant representation.
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
x_change = -5
elif key[pygame.K_RIGHT]:
x_change = 5
This doesn't keep track on was what pressed first or last, so if you're holding down both keys it'll go left. I've tried another solution that works pretty well. It basically a list that keeps track of the key presses in a list and moves the player based on the last key pressed.
import pygame
pygame.init()
screen = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()
x, y = 100, 100
car = pygame.Surface((32, 32))
velocity_dx = []
speed = 5
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
velocity_dx.insert(0, -speed)
elif event.key == pygame.K_RIGHT:
velocity_dx.insert(0, speed)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
velocity_dx.remove(-speed)
elif event.key == pygame.K_RIGHT:
velocity_dx.remove(speed)
try:
x += velocity_dx[0] # Take the first value from the list
except IndexError: # if list is empty, catch the IndexError.
pass
screen.fill((255, 255, 255))
screen.blit(car, (x, y))
pygame.display.update()
# print(velocity_dx) # Uncomment to see what's happening in action!

Related

On PyCharm my left key and right key isn't responding

#enable pygame mode
import pygame
pygame.init()
#create screen
screen = pygame.display.set_mode((900,600))
#Title + Logo
pygame.display.set_caption("Space Invader")
icon = pygame.image.load("chicken.png")
pygame.display.set_icon(icon)
#Player icon
player_icon = pygame.image.load("spaceship.png")
playerX = 400
playerY = 500
def player(x, y):
screen.blit(player_icon, (x, y))
#game loop
running = True
while running:
# backround colour RGB
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#If key pressed check wether its right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("key left pressed")
if event.key == pygame.K_RIGHT:
print("key right pressed")
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
print("key stroke has benn released")
#Player change in coordinates
playerX += 0
playerY += 0
player(playerX, playerY)
pygame.display.update()
I have been learning about pygame and game programing using python during this quarantine. I have been doing this by watching a tutorial on youtube. Please don't downgrade me I have tried harder to make my question better last time it was my first question and got 2 downgrades. Thankyou for your time.
It s a matter of Indentation. In your code the pygame.KEYDOWN event is only evaluated in case of event.type == pygame.QUIT. "Move" the pygame.KEYDOWN event handling:
running = True
while running:
# backround colour RGB
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# <--| INDENTATION
#If key pressed check wether its right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("key left pressed")
if event.key == pygame.K_RIGHT:
print("key right pressed")
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
print("key stroke has benn released")

pygame.time.set_timer() event reset?

I've got a little question...
Is there a reset of some sort for the pygame.time.set_timer()?
I've got it running okay but the issue is that I need the timer to reset back to 0 whenever a certain action is performed. As it's running now, the timer will trigger the movedownauto event every second(no matter what happens), but what I want it to do is reset when a key is pressed so that it will then wait one second AFTER the key is pressed to trigger the movedownauto event.
It would be ideal if something could be put into the if event.type == USEREVENT: section.
Example below ↓
pygame.time.set_timer(USEREVENT, 1000)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
# Figure out if it was an arrow key. If so
# adjust speed.
if event.key == pygame.K_LEFT:
x_speed = -40
elif event.key == pygame.K_RIGHT:
x_speed = 40
elif event.key == pygame.K_DOWN:
y_speed = 40
# User let up on a key
elif event.type == pygame.KEYUP:
# If it is an arrow key, reset vector back to zero
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_speed = 0
elif event.key == event.key == pygame.K_DOWN:
y_speed = 0
# Move the object according to the speed vector.
x_coord += x_speed
y_coord += y_speed
if event.type == USEREVENT:
movedownauto(screen, x_coord, y_coord)
else:
drawcharacter(screen, x_coord, y_coord)
clock.tick(tickspeed)
pygame.display.flip()
Thanks!
If you want to trigger the USEREVENT only once after a keypress, remove the pygame.time.set_timer(USEREVENT, 1000) line from the top and add pygame.time.set_timer(USEREVENT, 1000, True) inside the elif event.type == pygame.KEYDOWN: block.
If you set the third argument of pygame.time.set_timer to True, the event will be added to the event queue only once (note that this feature is only avaiable in pygame version 2)
If you want the USEREVENT to happen regulary and just "reset" the timer if a KEYDOWN happens, just remove the timer and add it again.
elif event.type == pygame.KEYDOWN:
pygame.time.set_timer(USEREVENT, 0)
pygame.time.set_timer(USEREVENT, 1000)
...

pygame - Unpress key on event.key

I am having a problem with pyGame (complete newbie here). I practice with event.key and would like to unpress / cut off key that is pressed continuously. I have tried to google it and checked this site, but that led to no promising results. Whole thing takes place in
if event.key == pygame.K_UP and isJumping == False:
(full lines 49 - 55)
## HOW TO UNPRESS K_UP IN CASE IT WAS PRESSED AND NOT RELEASED?
if event.key == pygame.K_UP and isJumping == False:
yChange -= 10
isJumping = True
elif event.key == pygame.K_UP and isJumping == True:
print("X")
This works just fine if up arrow is pressed once, but keeps on executing yChange in a loop in case it was not released - that of course is not desired at all. Could you help me with this please?
import pygame
pygame.init() # Initialize pyGame module
# Set screen dimensions
screenW = 800
screenH = 600
# Set color
AQUA = (155, 255, 255)
# Set FPS
FPS = 60
fpsClock = pygame.time.Clock()
# Set character
mainChar = pygame.image.load('p1_front.png')
mainCharX = screenH / 2 # char X position
mainCharY = screenW / 2 # char Y position
isJumping = False
xChange = 0
yChange = 0
MOVSPEED = 1
# Set backgrounds
mainBg = pygame.image.load('bg_castle.png')
mainBg = pygame.transform.scale(mainBg, (screenW, screenH))
# Set the window, param in a tuple is width / height
DISPLAYSURF = pygame.display.set_mode((screenW, screenH))
# Set window name (game title)
pygame.display.set_caption("Newbie training")
while True: # Main loop of the game
#set BG
DISPLAYSURF.blit(mainBg, (0,0))
# Events loop below
for event in pygame.event.get():
if event.type == pygame.QUIT: # Quit window when [x] is pressed
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
xChange += MOVSPEED
elif event.key == pygame.K_LEFT:
xChange -= MOVSPEED
## HOW TO UNPRESS K_UP IN CASE IT WAS PRESSED AND NOT RELEASED?
if event.key == pygame.K_UP and isJumping == False:
yChange -= 10
isJumping = True
elif event.key == pygame.K_UP and isJumping == True:
print("X")
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT:
xChange = 0
if event.key == pygame.K_UP:
yChange = 0
#print(event)
mainCharX += xChange
mainCharY += yChange
DISPLAYSURF.blit(mainChar, (mainCharX, mainCharY)) # Load character
pygame.display.update() #update window
fpsClock.tick(FPS) # FPS goes always after update
If you only want the player to be able to jump 10 'units' per up press then stop in place, you could simply set yChange to 0 each frame after you add it to mainCharY.
However, if you're looking for a more robust jumping system (button is pressed, player moves up for a few frames, then stops and falls back down) more is required.
To give you an idea: what if you had some logic at the end of each frame that checks if mainCharY > 0 (player is not on ground) and, if so, subtracts some number from yChange (as if gravity were pulling them down)?
In the above case, your code should avoid the repeating up press problem. It might be easier to just test (mainCharY > 0) instead of using an isJumping variable.
It seems you're misunderstanding how the event queue and event loop work. When you press a key, a single pygame.KEYDOWN event gets added to the event queue. Calling pygame.event.get empties the event queue and puts all events into a list over which you iterate with the for loop: for event in pygame.event.get():. That means pygame doesn't know that you're still holding the key, it will only see that you've pressed UP once. It will also notice that you release the key and add a pygame.KEYUP event to the queue.
In your case you're decreasing the yChange variable to -10 when you press the UP key. In the while loop mainCharY will then be decremented by -10 each frame and the character will move upwards. As soon as you release the key, the yChange is reset to 0 and the player character stops.
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
yChange = 0
To implement jumping in your game, you should add a GRAVITY constant which you add to your y-velocity each frame to accelerate downwards. When the character touches the ground, set the y-velocity to 0 and a variable (on_ground or something similar) to True, so that you know that the player can jump. When the player presses the jump key, you can set the y-velocity to a negative value and the sprite will start to move upwards until the GRAVITY pulls him down again. Here's a complete example.
I don't think it's likely at all that pygame could miss a key event.
I think the problem is that you're not setting isJumping to false anywhere, which stops the changing of yChange forever after the first press. If I'm interpreting this correctly, the following code should work:
if event.type == pygame.KEYDOWN:
... # Your other code
if event.key == pygame.K_UP and not isJumping: # "== False" is not necessary
yChange -= 10
isJumping = True
if event.type == pygame.KEYUP:
... # Your other code
if event.key == pygame.K_UP and isJumping:
yChange = 0
isJumping = False # <-- This is the addition to the code
One thing to keep in mind is that this jumping system won't look very natural. Look to #SamHolloway's answer for more clarification on this.

Player movement stops when direction reverses in Pygame

I am messing around with pygame and I am eventually working towards a pong clone. I implemented player movement with the arrow keys and when ever I switch from going up to immediately going down, my player freezes and won't move again until I press that direction key again. Here is my code:
import sys, pygame
pygame.init()
display_width = 640
display_height = 480
display = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Test Game")
black = (0,0,0)
white = (255,255,255)
clock = pygame.time.Clock()
running = True
class Player:
def __init__(self,x,y,hspd,vspd,color,screen):
self.x = x
self.y = y
self.hspd = hspd
self.vspd = vspd
self.color = color
self.screen = screen
def draw(self):
pygame.draw.rect(self.screen,self.color,(self.x,self.y,32,32))
def move(self):
self.x += self.hspd
self.y += self.vspd
player = Player(0,0,0,0,black,display)
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
player.hspd = 0
if event.key == pygame.K_LEFT:
player.hspd = 0
if event.key == pygame.K_UP:
player.vspd = 0
if event.key == pygame.K_DOWN:
player.vspd = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.hspd = 4
if event.key == pygame.K_LEFT:
player.hspd = -4
if event.key == pygame.K_UP:
player.vspd = -4
if event.key == pygame.K_DOWN:
player.vspd = 4
#Clear the screen
display.fill(white)
#Move objects
player.move()
#Draw objects
player.draw()
#Update the screen
pygame.display.flip()
print "I made it!"
pygame.quit()
sys.exit()
I suggest you work with key.get_pressed() to check for the current set of pressed keys.
In your scenario - when you press down and release up (in that order) - the speed is set to 0, so you need to inspect the keys pressed not just by the current event.
Here is a working version of the relevant part:
def current_speed():
# uses the fact that true = 1 and false = 0
currently_pressed = pygame.key.get_pressed()
hdir = currently_pressed[pygame.K_RIGHT] - currently_pressed[pygame.K_LEFT]
vdir = currently_pressed[pygame.K_DOWN] - currently_pressed[pygame.K_UP]
return hdir * 4, vdir * 4
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
player.hspd, player.vspd = current_speed()
#Clear the screen
display.fill(white)
#Move objects
player.move()
#Draw objects
player.draw()
#Update the screen
pygame.display.flip()
To expand on LPK's answer, your key down (for event.key == pygame.K_DOWN) is likely being processed before your key up (from event.key == pygame.K_UP) is processed. So while both are down (and you can confirm this), you may experience movement, until you release the up key.
your problem is here:
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
player.hspd = 0
if event.key == pygame.K_LEFT:
player.hspd = 0
if event.key == pygame.K_UP:
player.vspd = 0
if event.key == pygame.K_DOWN:
player.vspd = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.hspd = 4
if event.key == pygame.K_LEFT:
player.hspd = -4
if event.key == pygame.K_UP:
player.vspd = -4
if event.key == pygame.K_DOWN:
player.vspd = 4
I am guessing that your key event down is still consumed when u switch the keys immediately, meaning no other key down event is getting triggered as long as the first event didn't fire its key up event yet.
EDIT: maybe its better to check if the player is moving and if so just reverse speed . Then you would only need to check the down event.
Otherwise your event will be consumed and not checked properly.
For your method you would need to store the occurred key events since the last frame and check that list.

Move left or right to fast causes img to stick

I am making a spaceship invaders game in python 3 with pygame. I am currently having troubles with the spaceship sticking making me double tap a left or right arrow key for it to take effect. Here is my code:
import pygame
pygame.init()
display_width = 800
display_height = 600
black = (0, 0, 0)
white = (255, 255, 255)
#Window Size
gameDisplay = pygame.display.set_mode((display_width, display_height))
#Title Of Window
pygame.display.set_caption('A Bit Racey')
#FPS
clock = pygame.time.Clock()
spaceshipImg = pygame.image.load('SpaceShipSmall.png')
def spaceship(x,y):
gameDisplay.blit(spaceshipImg, (x,y))
x = (display_width * 0.45)
y = (display_height * 0.8)
x_change = 0
crashed = False
while not crashed:
# this will listen for any event every fps
for event in pygame.event.get():
if event.type == pygame.QUIT:
#change later
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
elif event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
x += x_change
gameDisplay.fill(white)
spaceship(x,y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
Every time a pygame.KEYUP event is detected for the left or right arrow key you reset x_change. Even when you hold down e.g. your right arrow key a single left arrow key press stops the movement of your spaceship.
To solve this problem you could use the pygame.key.get_pressed() method to get the state of all keyboard buttons. This function returns a sequence of boolean values indexed by pygames key constant values representing the state of every key on the keyboard.
Because you don´t need to call pygame.key.get_pressed() every time an event happens, the updated main loop should look like this:
while not crashed:
# this will listen for any event every fps
for event in pygame.event.get():
if event.type == pygame.QUIT:
#change later
crashed = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
#get the state of all keyboard buttons
pressedKeys = pygame.key.get_pressed()
#change position if pygame.K_LEFT or pygame.K_RIGHT is pressed
if pressedKeys[pygame.K_LEFT]:
x += -5
elif pressedKeys[pygame.K_RIGHT]:
x += 5
gameDisplay.fill(white)
spaceship(x,y)
pygame.display.update()
clock.tick(60)
Notice that a pygame.K_LEFT event has a higher priority than a pygame.K_RIGHT event. You could change this behavior by using two separate if blocks. Many thanks to #sloth for pointing this out!:
#change position if either pygame.K_LEFT or pygame.K_RIGHT is pressed
if pressedKeys[pygame.K_LEFT]:
x += -5
if pressedKeys[pygame.K_RIGHT]:
x += 5
I hope this helps you :)
add the following statement before x += x_change:
print (event.type, event.key, x)
this will print the event data and x position to the console.
try your script again, try holding down the left key for 3 seconds, then release, and repeat for the right key. See if you see multiple keydown events while holding down the keys. I think you should only see one keyup event upon release.

Categories

Resources