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!
for event in pygame.event.get():
if event.type == pygame.QUIT:
print('closing the window')
running = False
# key down for checking if a key is pressed.
if event.type == pygame.KEYDOWN:
print('some key is pressed')
if event.type == pygame.K_UP:
print("up key is pressed")
elif event.type == pygame.K_RIGHT:
print("Right key is pressed")
elif event.type == pygame.K_w:
print('w is pressed')
else:
print("does'nt recognize")
# key up for checking if a key is released.
if event.type == pygame.KEYUP:
print('some key is released')
if event.type == pygame.K_LEFT or event.type == pygame.K_RIGHT:
print('Keystroke is released')
I ran the code but this is the output:
some key is pressed
does'nt recognize
some key is released
some key is pressed
does'nt recognize
some key is released
closing the window
You are checking if event.type == pygame.K_RIGHT, however, you already know that event.type == pygame.KEYDOWN which is not equal to pygame.K_RIGHT. Instead, check event.key. This represents what key exactly is being pressed, while type just tells you that this is a keyboard event.
I want to change the text in the controls screen based on the key which the user presses.
how do I convert pygame.event.get() into a string that shows which key has been pressed?
preferably without many if staments
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
slectedKey = # get key name as a string
print(slectedKey)
The code of the pressed can be get by the event.key attribute.
The unicode representation for the key can be get by the event.unicode attribute.
See pygame.event module.
A unser friendly name of a key can be get by pygame.key.name():
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
print(pygame.key.name(event.key))
Note, if you want to evaluate if a certain key is pressed, the compare event.key to the constants defined in the pygame.key module:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
# [...]
elif event.key == pygame.K_RIGHT:
# [...]
Or store the key in a variable and use it continuously in the application loop:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
slectedKey = event.key
if slectedKey == pygame.K_UP:
# [...]
elif slectedKey == pygame.K_DOWN:
# [...]
If you want to evaluate if a key is is hold down, the use pygame.key.get_pressed():
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
# [...]
elif keys[pygame.K_a]:
# [...]
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.
# [...]
I know this question can be seen as a duplicate, but I spent some hours searching and figuring out what is wrong at my code.
My problem is that my object, called player, doesn't move constantly when left or right key is being held down:
for event in pygame.event.get():
if event.type == QUIT:
self.terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
self.terminate()
if event.key == K_LEFT or event.key == K_a:
self.moveRight = False
self.moveLeft = True
if event.key == K_RIGHT or event.key == K_d:
self.moveLeft = False
self.moveRight = True
if event.type == KEYUP:
if event.key == K_LEFT or event.key == K_a:
self.moveLeft = False
if event.key == K_RIGHT or event.key == K_d:
self.moveRight = False
# Move the player around
if self.moveLeft :
# Moves the player object to left with self.PLAYERMOVERATE pixels.
self.player.setLeftRight(-1 * self.PLAYERMOVERATE)
if self.moveRight :
self.player.setLeftRight(self.PLAYERMOVERATE)
I also tried this alternative:
while True:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.player.setLeftRight(-1 * self.PLAYERMOVERATE)
if keys[pygame.K_RIGHT]:
self.player.setLeftRight(self.PLAYERMOVERATE)
I think that the problem is that you are not handling the input in the main game loop.
In your code you seem to be handling the input inside a method of the object Player. This is not how input should be handled. In your second code example there is a while True: loop which will mean the loop is never exited from and thus the method's execution is never finished. I suspect that there may be a similar issue in your first example.
Instead you should:
Create all objects and classes.
Write the main game loop.
The main game loop should handle input, then process the logic of the game and then render whatever should be rendered.
Here is a short code example.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # Exit from pygame window
quit() # End python thread
if event.type == KEYDOWN:
if event.key == K_LEFT or event.key == K_a:
player.moveRight = False
player.moveLeft = True
if event.key == K_RIGHT or event.key == K_d:
player.moveLeft = False
player.moveRight = True
if event.type == KEYUP:
if event.key == K_LEFT or event.key == K_a:
player.moveLeft = False
if event.key == K_RIGHT or event.key == K_d:
player.moveRight = False
# Move player using method
if player.moveLeft:
# Move player
# ...
# Render player
I hope that this helped you and if you have any further questions please feel free to post them in the comment section below!