I have a function that detects if i press a key in pygame, but it only detects one key? - python

I have a function that detects key presses but, when i use the function and detect 'a' it detects but if i detect 'd' it doesnt detect it, but if i put the function that detects the key 'd' before the function that detects the key 'a' it detects 'd', why so?
here is my code:
keys = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','space','1','2','3','4','5','6','7','8','9','0']
pygame_keys = [pygame.K_a,pygame.K_b,pygame.K_c,pygame.K_d,pygame.K_e,pygame.K_f,pygame.K_g,pygame.K_h,pygame.K_i,pygame.K_j,pygame.K_k,pygame.K_l,pygame.K_m,pygame.K_n,pygame.K_o,pygame.K_p,pygame.K_q,pygame.K_r,pygame.K_s,pygame.K_t,pygame.K_u,pygame.K_v,pygame.K_w,pygame.K_x,pygame.K_y,pygame.K_z,pygame.K_SPACE,pygame.K_1,pygame.K_2,pygame.K_3,pygame.K_4,pygame.K_5,pygame.K_6,pygame.K_7,pygame.K_8,pygame.K_9,pygame.K_0]
def key_pressed(key_press,one_click =False):
global key_function_run
if one_click:
key_function_run = True
if not one_click:
if kb.is_pressed(key_press):
return True
if one_click:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
for i in range(len(keys)):
if event.type == pygame.KEYDOWN:
if key_press == keys[i]:
if event.key == pygame_keys[i]:
print(i)
return True
pass
And here is how i am using the function:
if x == 205:
player_lane = 2
if x == 60:
player_lane = 1
if x == 347:
player_lane = 3
#player movement
if peasy.key_pressed('a',True) and player_lane == 2:
x = 60
if peasy.key_pressed('a',True) and player_lane == 3:
x = 205
if peasy.key_pressed('d',True) and player_lane == 2:
x = 347
if peasy.key_pressed('d',True) and player_lane == 1:
x = 205

Make a dictionary from your lists:
key_dict = dict(zip(keys, pygame_keys))
And use pygame.key.get_pressed:
def key_hold(keys, key):
return keys[key_dict[key]]
keys = pygame.key.get_pressed()
is_a = key_hold(keys, 'a')
is_d = key_hold(keys, 'd')
If you want to use the KEYDOWN event, you have to be aware that 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. [...]
So you can call pygame.event.get only once per frame. Also see Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?. However you can use unicode property of the KEYDOWN event:
def key_down_event(event_list, c):
return any(e for e in event_list if e.type == pygame.KEYDOWN and e.unicode == c)
event_list = pygame.event.get()
is_a = key_down_event(event_list, 'a')
is_d = key_down_event(event_list, 'd')
If you want a function that detects both whether a key is held down or has been pressed, you need to count the frames of how long a key is pressed, for each key. Return True if the count for a key is 1 when you want to determine if the key was just pressed:
import pygame
key_count = {}
def key_pressed(keys, key, one_click):
pressed = keys[key]
key_count[key] = (key_count.get(key, 0) + 1) if pressed else 0
return key_count[key] == 1 if one_click else pressed
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
a_once = key_pressed(keys, pygame.K_a, True)
d_hold = key_pressed(keys, pygame.K_d, False)
if a_once:
print(f'key event: {pygame.key.name(pygame.K_a)}')
if d_hold:
print(f'key pressed: {pygame.key.name(pygame.K_d)}')
pygame.display.flip()
pygame.quit()
exit()

You shouldn't need to make a custom function for input handling, you can use something like this:
running = True
def main():
# Your normal game loop
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Gets a list of the currently pressed keys,
# this is updated because we put it in the while loop
kbd = pygame.key.get_pressed()
if kbd[pygame.K_a]:
print("I just pressed the A button!") # You can run here whatever ya want
Edit: I realized OP wanted to use pygame.KEYDOWN instead of pygame.key.get_pressed(), so in that case, you can use something like this
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
print("Pressed D!")
Hope I helped. If you have any questions, just leave a comment/reply/whatever!

Related

why doesn't my window close when I press the escape key

why doesn't my window close when I press the escape key:
import pygame
pygame.display.init()
pygame.display.set_mode(size=(500, 500))
pygame.display.set_caption("hi")
x = 1
while True:
if pygame.key.get_mods() & pygame.K_ESCAPE:
x = 2
if x == 2:
pygame.quit()
You need an event-loop in your while-loop like so:
import pygame
pygame.display.init()
pygame.display.set_mode(size=(500, 500))
pygame.display.set_caption("hi")
x = 1
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: # uses the small 'x' on the top right to close the window
pygame.quit()
if event.type == pygame.KEYDOWN: # processes all the Keydown events
if event.key == pygame.K_ESCAPE: # processes the Escape event (K_A would process the event that the key 'A' is hit
x = 2
if x == 2:
pygame.quit()
pygame.display.update()
I also added pygame.display.update(), which should normally be in your code.

Detect single key press using key.get_pressed()

I am trying to detect a single key press no matter how long the key is held down. Example, if the 'a' key is held down for 3 seconds, my current program would print this:
key pressed
'aaaaaaaaaaaaa'
key released
I am trying to get it to where it would only allow a single action per press/release cycle:
key pressed
'a'
key released
key pressed
'a'
key released
What am I doing wrong? Thank you
def update(self):
space_released = True
space_pressed = False
elif event.type == KEYUP:
if event.key == K_SPACE:
self.space_released = True
elif event.type == KEYDOWN:
if event.key == K_SPACE:
self.space_released = False
key = pygame.key.get_pressed()
while space_released == True:
# Print key pressed
return
space_released = False
Use pygame.key.set_repeat() to control how held keys are repeated:
When the keyboard repeat is enabled, keys that are held down will generate multiple pygame.KEYDOWN events. [...]
[...] To disable key repeat call this function with no arguments or with delay set to 0.
Just call pygame.key.set_repeat() to disable repeating keys:
pygame.key.set_repeat()
run = True
while run:
clock.tick(60)
space_released = False
space_pressed = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == KEYUP:
if event.key == K_SPACE:
space_released = True
elif event.type == KEYDOWN:
if event.key == K_SPACE:
space_pressed = True
# [...]
If you want to do something similar with pygame.key.get_pressed (), you have to save the state of pygame.K_SPACE and compare the previous (space_was_pressed) state with the current state (space_is_pressed):
space_was_pressed = 0
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
key = pygame.key.get_pressed()
space_released = True
space_pressed = False
space_is_pressed = key[pygame.K_SPACE]
if space_was_pressed != space_is_pressed:
space_released = not space_is_pressed
space_pressed = space_is_pressed
space_was_pressed = space_is_pressed

My pause statement is not working for pygame loop

My collide_rect function is not working as I expect to be. The problem is when press the key 'r', it should be able to reset everything and continue the game. But when I actually press the key 'r', it does not change anything when I add in the pause statement. I want to have the game pause when two of the sprites I have(ball, obstacle) collide. After the user inputs the letter 'r', it should go back to running and reset position for both sprites. The error I am getting is when I press the key 'r', it does not change anything on the surface.
This is my while loop:
paused = False
def display_text(text):
font = pygame.freetype.Font('helvetica.ttc', 32)
text_attributed = font.render_to(gameDisplay, (300,300), text, black)
while not crashed:
time = pygame.time.get_ticks()
obstacle.change_x()
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
ball.jump_true()
if event.key == pygame.K_SPACE:
ball.jump_true()
if event.key == pygame.K_r:
paused = not paused
if ball.collide == True:
gameDisplay.fill(white)
display_text('You Lost! type "R" to restart')
paused = True
if paused == True:
ball.reset_position()
obstacle.reset_position()
pygame.display.flip()
clock.tick(20)
else:
ball.jump()
ball.test_collision(obstacle)
gameDisplay.fill(white)
ball.update()
obstacle.update()
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()
Don't overcomplicate things. You don't need multiple event loops. Use 1 main loop, 1 event loop and a state which indicates if the game is paused. e.g.:
paused = False
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r
# Toggle pause
paused = not paused
if paused:
# "pause" mode
# [...]
else
# "run" mode
# [...]
# update display etc.
# [...]

Multiple instances of pygame.event.get()

There are two for event in pygame.event.get(): instances. It doesn't work inside the second one. I guess that calling the function twice will not work. What should be done here? By the way this is a function to move a piece from square to square in a board game.
def movement_one(blit1,charac1,screen,squareblitter,boardcoord,placecheck_True):
global mouse1, mouse1_des
run1=True
while run1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse1 = pygame.mouse.get_pos()
for i in range(80):
if squareblitter[i].collidepoint(mouse1):
collided = i
break
print "wow"
print i
print collided in placecheck_True
if collided in placecheck_True:
#checks if the square is occupied or not
print "wiw"
for event in pygame.event.get():
print "wtf"
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse1_des = pygame.mouse.get_pos()
print "omg"
squareblitter[i]
pygame.display.update()
for i in range(80):
if squareblitter[i].collidepoint(mouse1_des):
screen.blit(placecheck_True[collided], squareblitter[i])
placecheck_True.update[i]=placecheck_True[collided]
pygame.display.update()
run1=False
break
else:
break
Calling pygame.event.get() again while handling an event from a previous call usually won't work. It's unclear from your code precisely what you're trying to accomplish. However, I suggest you rry moving the code for processing pygame.MOUSEBUTTONDOWN events when there's a collision that's currently in you inner for event loop to the outer one (and remove the inner for event loop altogether).
Here's what I mean (untested, of course):
def movement_one(blit1, charac1, screen, squareblitter, boardcoord, placecheck_True):
global mouse1, mouse1_des
run1 = True
while run1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse1 = pygame.mouse.get_pos()
for i in range(80):
if squareblitter[i].collidepoint(mouse1):
collided = i
break
print "wow"
print i
print collided in placecheck_True
if collided in placecheck_True:
mouse1_des = pygame.mouse.get_pos()
print "omg"
squareblitter[i]
pygame.display.update()
for i in range(80):
if squareblitter[i].collidepoint(mouse1_des):
screen.blit(placecheck_True[collided], squareblitter[i])
placecheck_True.update[i] = placecheck_True[collided]
pygame.display.update()
run1 = False # not sure you should do this...
break

How do I make a game object move continuously as long as the key is pressed?

I am trying to make a game object (here, the welcome text) move as long as the key is pressed on the keyboard. But in this code of mine,
import pygame , sys
from pygame.locals import *
pygame.init()
WHITE = (255 , 255 , 255)
RED = (255 , 0 , 0)
DISPLAYSURF = pygame.display.set_mode((800 , 400))
pygame.display.set_caption('Welcome Tanks')
#render(text, antialias, color, background=None)
fontObj = pygame.font.SysFont('serif' , 40)
text = fontObj.render('Welcome Folks' , True , RED )
x = 150
y = 29
while True:
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(text ,(x , y))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN or event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
elif event.key == K_DOWN:
y += 15
elif event.key == K_UP:
y -= 15
elif event.key == K_RIGHT:
x += 14
elif event.key == K_LEFT:
x -= 15
else:
x = 150
y = 29
pygame.display.update()
The object moves only once, even though the key is continuously pressed for a long time. In other words, the object changes its position only once when the keyboard button is pressed. I want it to move continuously while I hold the key.
Which event should I look for instead of event.KEYDOWN?
I suggest you to use the key.get_pressed(), e.g.
while True:
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(text ,(x , y))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN or event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
if pygame.key.get_pressed()[K_LEFT]:
x -= 15
if pygame.key.get_pressed()[K_RIGHT]:
x += 14
if pygame.key.get_pressed()[K_UP]:
y -= 15
if pygame.key.get_pressed()[K_DOWN]:
y += 15
pygame.display.update()
pygame.key.get_pressed()
Returns a sequence of boolean values representing the state of every
key on the keyboard. Use the key constant values to index the array. A
True value means the that button is pressed.
Getting the list of pushed buttons with this function is not the
proper way to handle text entry from the user. You have no way to know
the order of keys pressed, and rapidly pushed keys can be completely
unnoticed between two calls to pygame.key.get_pressed(). There is also
no way to translate these pushed keys into a fully translated
character value. See the pygame.KEYDOWN events on the event queue for
this functionality.
Also you can take a look at doc
keyState = pygame.key.get_pressed()
Declare that, and then you use keystate:
if KeyState()[K_DOWN]:
y += 15
You could try:
if key.get_pressed()
down = True
while down = True:
y+= 15
Then get FPS clock so it does not just flow over the screen!

Categories