Get_Pressed behaving oddly - python

I'm having some trouble with the keyboard events in my programme. Long story short I was using pygame.KEYDOWN events but then heard from pretty much everyone that get_pressed() is a better suited option. I changed my code accordingly but have run into a few problems
Firstly:
If I am holding two keys but then only release one, pygame for some reason thinks that I have released both. This means that diagonal movement is a pain to implement
Secondly:
Diagonal movement IS working but only in certain cases when:
I'm moving up and down and hold left or right
It does not (for some reason) work if I'm going left or right and hold up or down
Here is the code I've been using:
while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
keys = pygame.key.get_pressed()
if (keys[K_KP6]):
square.spd_x+=5
if square.spd_x > 5: # Put these speed limits in a function
square.spd_x = 5
elif (keys[K_KP4]):
square.spd_x -=5
if square.spd_x <-5:
square.spd_x = -5
elif (keys[K_KP8]):
square.spd_y -=5
if square.spd_y <-5:
square.spd_y = -5
elif (keys[K_KP2]):
square.spd_y +=5
if square.spd_y >5:
square.spd_y = 5
else:
square.spd_x = 0
square.spd_y = 0
If anyone could shed light on the issue I'd be extremely grateful and I thank you very much for attempting to answer
Thank you :D

I don't know if this will work, but it's worth a shot.
while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
keys = pygame.key.get_pressed()
if (keys[K_KP6]):
square.spd_x=5
else:
square.spd_x=0
if (keys[K_KP4]):
square.spd_x-=5
if (keys[K_KP8]):
square.spd_y=-5
else:
square.spd_y=0
if (keys[K_KP2]):
square.spd_y +=5
Let me know if it works.

Related

Some inputs are being missed in pygame.event.get()

NVM FIXED: It was my computer palm rejection that prevented a left click from being registered when I was clicking other keyboard keys. So check that!
ORIGINAL QUESTION:
I am calling pygame.event.get() in my core game loop once per frame, and it seems to be get my WASD inputs just fine with almost zero delay, but left mouse click inputs are often missed. It almost seems like all other inputs except WASD feel very delayed?
Here is the relevant code:
def processInput(self):
events = pygame.event.get()
if len(events) != 0:
print(events)
for event in events:
match event.type:
case pygame.QUIT:
self.running = False
break
case pygame.KEYDOWN:
self.inputs.append(event.key)
case pygame.KEYUP:
self.inputs.remove(event.key)
case pygame.MOUSEBUTTONDOWN:
print("button down!")
b = event.button
a = -1
match(b):
case 1:
a = pygame.BUTTON_LEFT
case 2:
a = pygame.BUTTON_MIDDLE
case 3:
a = pygame.BUTTON_RIGHT
case _:
pass
self.inputs.append(a)
case pygame.MOUSEBUTTONUP:
b = event.button
r = -1
match(b):
case 1:
r = pygame.BUTTON_LEFT
case 2:
r = pygame.BUTTON_MIDDLE
case 3:
r = pygame.BUTTON_RIGHT
case _:
pass
self.inputs.remove(r)
case _:
pass
The print statement in the fourth case is not being printed, so I know it's not with my input processing later down the loop. Any help or insight would be appreciated!
I've tried rebinding the action to another keyboard key instead of left click and it feels delayed too. Only the WASD keys seem to be working with no problems. So it does not seem like an issue with MOUSEBUTTONDOWN specifically with pygame, but then I have no idea what it is then.
It was my computer palm rejection that prevented a left click from being registered when I was clicking other keyboard keys. So check that!

What is the solution to this type error :list indices must be integers or slices, not str?

I am a beginner so pardon if I haven't asked the questions according to the standard
FEW DAYS AGO, I have created a program but it shows the following error, I did some research but none of the answers were not of this type of question, the error is as follows:
if apple["x"]==snakeCoords[head]["x"] and apple["y"]==snakeCoords[head]["y"]:
TypeError: list indices must be integers or slices, not str
and my code was:
def run2(score,run):
global appleX,appleY,snakeCoords
startX=random.randint(20,cellWidth)
startY=random.randint(20,cellHeight)
apple=randomlocation()
appleX=apple['x']*cell_s
appleY=apple['y']*cell_s
snakeCoords=[{"x":startX,"y":startY},
{"x":startX-1,"y":startY},
{"x":startX-2,"y":startY}]
direction=RIGHT
assert win_w % cell_s==0
assert win_h % cell_s==0
while run:
if snakeCoords[head]['x']==19 or snakeCoords[head]['y']==19:
gameover(window)
pygame.time.wait(500)
run=False
terminate()
sys.exit()
if snakeCoords[head]['x']==win_w-20 or snakeCoords[head]['y']==win_h-20:
gameover(window)
pygame.time.wait(500)
run=False
terminate()
sys.exit()
for body in snakeCoords[1:]:
if snakeCoords[head]['x']==body['x'] and snakeCoords[head]['y']==body['y']:
gameover(window)
pygame.time.wait(500)
terminate()
sys.exit()
if direction==UP:
move={'x':snakeCoords[head]['x']-1,'y':snakeCoords[head]['y']}
if direction==DOWN:
move={'x':snakeCoords[head]['x']+1,'y':snakeCoords[head]['y']}
if direction==RIGHT:
move={'x':snakeCoords[head]['x'],'y':snakeCoords[head]['y']+1}
if direction==LEFT:
move={'x':snakeCoords[head]['x'],'y':snakeCoords[head]['y']-1}
snakeCoords.insert(0,move)
if apple['x']==snakeCoords[head]['x'] and apple['y']==snakeCoords[head]['y']:
apple=randomlocation()
drawgame.drawapple(red)
score+=1
if appleX==snakeCoords[head]['x'] and direction==RIGHT:
newhead=[{'x':startX-3,'y':startY}]
snakeCoords+=newhead
if appleX==snakeCoords[head]['x'] and direction==LEFT:
newhead=[{'x':startX+3,'y':startY}]
snakeCoords+=newhead
if appleY==snakeCoords[head]['y'] and direction==UP:
newhead=[{'x':startX,'y':startY+3}]
snakeCoords+=newhead
if appleY==snakeCoords[head]['y'] and direction==DOWN:
newhead=[{'x':startX,'y':startY-3}]
snakeCoords+=newhead
pygame.display.update()
if score==10:
gameover(window)
pygame.time.wait(500)
for event in pygame.event.get():
if event.type==pygame.QUIT:
run=False
terminate()
sys.exit()
if event.type==KEYDOWN:
if event.key==K_RIGHT and direction!=LEFT:
direction=RIGHT
elif event.key==K_LEFT and direction!=RIGHT:
direction=LEFT
elif event.key==K_UP and direction!=DOWN:
direction=UP
elif event.key==K_DOWN and direction!=UP:
direction=DOWN
elif event.key==K_ESCAPE :
terminate()
sys.exit()
else:
print("Invalid Key Pressed")
if __name__=="__main__":
main(run)
in apple the code goes like this:
apple=randomlocation()
def randomlocation():
return {"x":random.randint(20,cellWidth),
"y":random.randint(20,cellHeight)}
in snakecoords the code goes like this:
startX=random.randint(20,cellWidth)
startY=random.randint(20,cellHeight)
snakeCoords=[{"x":startX,"y":startY},
{"x":startX-1,"y":startY},
{"x":startX-2,"y":startY}]
and cell width and height are:
win_w =640
win_h =640
cell_s =20
cellWidth=int(win_w/cell_s)-1
cellHeight=int(win_h/cell_s)-1
Please guide me.
I suggest coding it like
run = True
while run :
for event in pygame.event.get():
if event.type==pygame.QUIT:
run = False
Try exit pygame:
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()
The issue is caused by the line:
snakeCoords.insert(0,move)
because move is a list with one element. The element is a dictionary
move=[{'x':snakeCoords[head]['x'],'y':snakeCoords[head]['y']-1}]
There are 2 possibilities to solve the issue:
Use the asterisk(*) operator to unpacking the Lists:
snakeCoords.insert(0, move)
snakeCoords.insert(0, *move)
Make move a dictionary, rather than a list with one element that is a dictionary
if direction == UP:
move = {'x':snakeCoords[head]['x']-1,'y':snakeCoords[head]['y']}
if direction == DOWN:
move = {'x':snakeCoords[head]['x']+1,'y':snakeCoords[head]['y']}
if direction == RIGHT:
move = {'x':snakeCoords[head]['x'],'y':snakeCoords[head]['y']+1}
if direction == LEFT:
move = {'x':snakeCoords[head]['x'],'y':snakeCoords[head]['y']-1}
snakeCoords.insert(0, move)

I made velocity changing to make dash but want to add here some dash-lenght limit

so I made my character(player) to change its velocity faster if I press 'L shift' while pressing 'left key' or 'right key' at the same time.
The problem is, I wanna make this 'dash' to stop when it reached to the limit I set. I want my character not to dash more than 400 at once. Is there any possible method I can do with..? because I tried many but I still couldn't find anything works.
Here's part of my mainloop where the dash is set. char is defined before the loop.
while run:
clock.tick(20)
for event in pygame.event.get():
keys = pygame.key.get_pressed()
mods = pygame.key.get_mods()
if event.type == pygame.QUIT:
run = False
elif keys[pygame.K_LEFT] and mods & pygame.KMOD_LSHIFT or keys[pygame.K_RIGHT] and mods & pygame.KMOD_LSHIFT:
print("pressed: SHIFT")
char.vel = 20
#I wanna set dash limit to 400px but evry try sitll is all failled..
else:
char.vel = 5
It's fairly easy to use a real-time millisecond limit to a dash. Then you can calibrate the time to however longer you wish the dash to be.
In the code below I've set this time limit to DASH_TIME_LIMIT. The player char has a new member variable named char.dash_finish. When the dash starts, we put the time limit for the dash in here. Then in the main loop we're checking each frame to see if the current time is after this time, which indicates the time limit has expired.
To start a dash, first we check that they aren't dashing already. Then the dash_finish time is simply "now" plus some milliseconds in the future.
DASH_TIME_LIMIT = 700 # milliseconds
for event in pygame.event.get():
keys = pygame.key.get_pressed()
mods = pygame.key.get_mods()
if event.type == pygame.QUIT:
run = False
elif keys[pygame.K_LEFT] and mods & pygame.KMOD_LSHIFT or keys[pygame.K_RIGHT] and mods & pygame.KMOD_LSHIFT:
print("pressed: SHIFT")
if ( char.dash_finish == None ): # Not already dashing?
char.vel = 20
char.dash_finish = pygame.time.get_ticks() + DASH_TIME_LIMIT
# else:
# char.vel = 5
# has the dash-time expired?
time_now = pygame.time.get_ticks()
if ( char.dash_finish == None ):
char.vel = 5
elif ( time_now > char.dash_finish ):
# dash has now finished
char.dash_finish = None
char.vel = 5
clock.tick(20)
Using a time limit is easier than counting the number of pixels traversed by the player each frame.
Instead of measuring pixels you can make a variable called dash_count and set it to zero at first and make it increase by one wheneverthe character dashes. This is possible with a while loop:
while dash_count <= 400:
pass
# make your character dash over here

Values are being passed correctly however selection statements do not work properly

I've been recently trying to code a quick game which involves binary to hex conversion. I've set up some of the basic structure of the code but I've stumbled upon a problem: My selection statement in the game's entry point doesn't work as intended even though the values should be passed on correctly
What I've tried:
I tried "debugging" the program by adding print statements in between the function and statements, eg:
if event.key == pygame.K_KP_ENTER:
print('enter')
print(key_value)
key_value = 1
print(key_value)
The values when printed are correct, which are used in the game's while loop point:
while running:
if EventHandler.get_key_pressed() == 1:
print('1')
elif EventHandler.get_key_pressed() == 2:
print('2')
Changed the conditions of the statement, still got the same results eg:
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_KP_ENTER:
print('enter')
key_value = 2
elif event.key == pygame.K_SPACE:
print('space')
key_value = 1
Changed the get_key_pressed() function to a non-static one, still had the same results.
Went back to basic python tutorials to make sure my indentation and structuring/usage of selection statements are correct.
From my observations, only the first if statement after the while loop in works, however I'm not sure as to why that happens when I think I formatted my code properly.
Code:
main.py
import pygame
from Include.src.event_handler import EventHandler
# other imports go here, not related to problem.
# Global Variables
running = True
# Object creations, not really related as well
game = Game() # initialise pygame, settings and assets
screen = game.get_screen() # get screen bounds/object
while running:
if EventHandler.get_key_pressed() == 1: # Issue here
print('1')
elif EventHandler.get_key_pressed() == 2:
print('2')
pygame.display.flip()
pygame.display.update()
event_handler.py
import pygame
class EventHandler:
#staticmethod
def get_key_pressed():
key_value = 0
for event in pygame.event.get():
if event.type == pygame.QUIT:
print('Thanks for debugging me or playing idk')
pygame.quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_KP_ENTER:
print('enter')
key_value = 1
elif event.key == pygame.K_SPACE:
print('space')
key_value = 2
return key_value
Expected output
Person presses space, space and 2 is printed.
Person presses enter, enter and 1 is printed.
Actual output
Space pressed, only space is outputted.
Enter pressed, both enter and 1 is outputted.
Thank you so much!
For anyone looking back to this post, I've found the answer:
As #jasonharper said, the value was being thrown since the function was being called again
while running:
e = EventHandler.get_key_pressed() # make it constant
if e == 1:
print('1')
elif e == 2:
print('2')

Cant get animation to stop after certain period of time

I'm trying to run some animations using pygame and pyganim and I want them to run when a key is pressed for a certain period of time and then stop. This is what I've got so far but I cant get the if block at the bottom to trigger, which should stop the animation. I'm assuming the time_now variable keeps updating so it's never greater the time_end. What is wrong with my code?
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_r:
time_now = time.time()
time_end = time.time() + 5
runRight.stop()
runLeft.stop()
rollRight.stop()
rollLeft.stop()
standStill.stop()
unsheathSword.play()
if time_now >= time_end:
print('stop')
unsheathSword.stop()
standStill.play()
First, your indentation is wrong. The line while True: should not be on the same indentation level as the second line.
Your example doesn't work because of
time_now = time.time()
time_end = time.time() + 5
It's never the case that time_now >= time_end; if you plug in the values, it's time.time() >= time.time() + 5, which is obviously always False. That's like saying that 55 >= 55 + 5, which is 55 >= 60, which is always False.
You also define both times with time.time() and at the same place that you use them, which will never let one of them evolve in time separately compared to the other. I suggest splitting the event trigger from the event:
unsheathingSword = False
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_r:
time_unsheath_end = time.time() + 5
unsheathingSword = True
runRight.stop()
runLeft.stop()
rollRight.stop()
rollLeft.stop()
standStill.stop()
unsheathSword.play()
if unsheathingSword and time.time() >= time_unsheath_end:
print('stop')
unsheathSword.stop()
standStill.play()
unsheathingSword = False
Here unsheathingSword = False prevents that second block from infinitely executing. There are better ways of doing this, but I hope this will help you for now.
An additional benefit of spliting the things that trigger something from the handling of the consequences, is that it allows for much easier coding later on.
Putting these two blocks of code into functions is probably even better.

Categories