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.
Related
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
I know the title is not very clear, but I don't know what else I can say.
I have a player attacking, and when he is done attacking, I start a timer for 1 second, so we have to wait one second before attacking again. It wasn't working (we could attack only once) and I didn't know why, so I added print(self.between_two_attacks())and everything worked fine, I could attack, wait one second and attack again.
Here is the program, I don't know if it is enough because I have no idea where the bug comes from.
def between_two_attacks(self):
if self.after_attack_max == 0:
self.after_attack_max = pg.time.get_ticks() + 1000
print("set timer")
else:
after_attack = pg.time.get_ticks()
print("start timer")
if after_attack >= self.after_attack_max:
print("can attack again")
self.can_attack = True
self.after_attack_max = 0
def draw(self, win):
print(self.between_two_attacks())
if (self.attackcount + 1) >= 5:
self.attackcount = 0
self.between_two_attacks()
self.action = STAND_UP
self.arme = LIGHTSABER_OUT
self.stops_attacking = True
self.can_attack = False
if self.action == ATTACKING:
win.blit...
Run = True
While Run:
for event in pg.event.get():
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE and player.can_attack == True:
player.action = ATTACKING
If anything isn't clear in this part of the program, just tell me and I'll try to explain. Thanks for your help :)
The method between_two_attacks has to be invoked, before the state of self.can_attack is retrieved. self.can_attack is set in between_two_attacks. If the method is not called, the self.can_attack will never become True.
When you do print(self.between_two_attacks()), the self.between_two_attacks() is called.
Furthermore, the method can be simplified:
self.can_attack has to be set if self.after_attack_max == 0 or if the current time is greater than self.after_attack_max.
If self.can_attack is set then compute the restart the timer. If it is not set then it has to be evaluated. Initially self.after_attack_max is 0. If the current time is greater than self.after_attack_max, attacks have to be allowed and the timer has to be started again:
def between_two_attacks(self):
current_time = pg.time.get_ticks()
if self.can_attack:
self.after_attack_max = current_time + 1000
elif current_time > self.after_attack_max:
self.can_attack = True
self.after_attack_max = current_time + 1000
Note, self.after_attack_max is only set in between_two_attacks, do not reset it anywhere else.
When you print self.between_two_attacks() the self function gets called and executed. Now, if you added the whole line it means that this function was not executed at this point before and now it is, so if you remove print and left only function at the same location you should get the same behaviour.
I do not know if I manage to explain my thought so here as a quick example:
x = 5
def change_x():
global x
x+=10
print(x)
print(change_x())
print(x)
if you remove print() you will get same result.
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')
I want to change the value of a bool after some time when a user hits enter, whilst keeping the program running.
Pygame's delay or timers don't work as they stop the whole code or repeats a user event over and over again.
Although pygame has no function to wait while allowing the program to run, there are several ways of doing it without pygame. You can import time, a module that comes with python used for getting the current time. It has a function, time.time() which returns the amount of seconds since a set time. Therefore, you can do x = time.time() when the user hits enter, and you continuously check to see if time.time() - x <= delay in the game loop, and change the value of your boolean if it is true. For example:
import pygame, time, sys
screen = pygame.display.set_mode((100,100))
timer = False # timer is true after the user hits enter and before your boolean changes
delay = 1 # whatever your delay is (seconds)
bool = False
while True: # game loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:
x = time.time() # x is the time when you press enter
timer = True # the timer is activated
print(bool)
if timer:
if time.time() - x >= delay: # if the amount of time since enter was pressed is the delay
bool = True #change bool value
This code will wait till you press enter, and then, one second later, change the boolean. If you add anything in the game loop, it will still run while the timer is active. This works because time.time() gets the current time, and if the difference between the current time and the time when the user pressed enter (represented as x) is equal to the delay, then that much time passed since the user hit enter and it it changes the boolean.
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.