So, I have a problem, I don't fully understand the event that is needed to be given to a timer command anyway, it doesn't say anywhere online, to where I searched for hours. So I just used what most people seemed to be using 'USEREVENT + 1'. I'm not sure if it is correct, but my timer is not working. Am I using it correctly? Here is my code:
nyansecond=462346
nyanint=0
spin=0
aftin=452345
def nyanmusic(nyansecond,nyanint,spin):
if nyanint == 0:
nyansound.play()
nyanint= 1
elif nyanint == 1:
nyansecond = pygame.time.set_timer(USEREVENT+1,7000)
if nyansecond < 200 and spin == 1:
spin = 0
nyansecond = pygame.time.set_timer(USEREVENT+1,7000)
elif nyansecond > 6500 and nyansecond < 100000 and spin == 0:
spin = 1
nyansoundm.play()
return nyansecond,nyanint,spin
I then def it into my code on the second page I implemented (which works fine). It runs the nyansound, but doesn't run nyansoundm after 6.5 seconds (6500 milliseconds). I'm making this program to help me learn the basics of python and pygame, before moving on to more complex stuff. I can also use it when I want to listen to nyan cat or other looped songs without having to go on youtube and waste precious bandwidth. Don't worry about that, though.
Oh, and here is the code I have put into my loop, although I do not think this matters too much:
#music
nyansecond,nyanint,spin = nyanmusic(nyansecond,nyanint,spin)
Let's recap what pygame.time.set_timer does:
pygame.time.set_timer(eventid, milliseconds): return None
Set an event type to appear on the event queue every given number of milliseconds. The first event will not appear until the amount of time has passed.
Every event type can have a separate timer attached to it. It is best to use the value between pygame.USEREVENT and pygame.NUMEVENTS.
pygame.USEREVENT and pygame.NUMEVENTS are constants (24 and 32), so the argument eventid you pass to pygame.time.set_timer should be any integer between 24 and 32.
pygame.USEREVENT+1 is 25, so it's fine to use.
When you call pygame.time.set_timer(USEREVENT+1,7000), the event with eventid 25 will appear in the event queue every 7000ms. You didn't show your event handling code, but I guess you do not check for this event, which you should do.
As you can see, pygame.time.set_timer returns None, so your line
nyansecond = pygame.time.set_timer(USEREVENT+1,7000)
doesn't make sense since nyansecond will always be None, and hence comparing it against an integer
if nyansecond < 200 ...
is pointless.
If you want to play a sound every 6.5 seconds using the event queue, simpy call pygame.time.set_timer once(!):
PLAYSOUNDEVENT = USEREVENT + 1
...
pygame.time.set_timer(PLAYSOUNDEVENT, 6500)
and check the event queue for this event in your main loop:
while whatever: # main loop
...
# event handling
if pygame.event.get(PLAYSOUNDEVENT): # check event queue contains PLAYSOUNDEVENT
nyansoundm.play() # play the sound
Related
If the pygame program is just a basic entity you can move normally with arrow keys, how could i make it so that if space is pressed, based on the arrow key that was being held at the moment of pressing, a player dashes slightly to the specified direction? My idea is that when the space is pressed, program checks if other keys are being held down and based on that it rapidly increases the x and/or y coordinate and then stops at specific time, but I don't know how to make it stop as all of this is happening inside a main game loop. Any insight is highly appreciated.
You can use time.perf_counter.
So for using that function you will need to import module time
import time
And now you can store the value of time.perf_counter in a variable when space is pressed.
import time
jumping = False
start_time = 0
while True:
if ("space is pressed"): # Replace condition with what you want
jumping = True
start_time = time.perf_counter()
# Add your code here
if jumping:
# change of x, y and other jumping mechanism code here
if jumping and time.perf_counter() - start_time > 1: # Replace 1 with the amount you want this if condition to trigger, also add value in seconds
jumping = False
I'm not sure what your code is like, but this is how I'd go about it:
def dash(self):
keys = pygame.keys.get_pressed()
if keys[pygame.K_SPACE] and not self.dashing and self.jumping:
# ^^ Can be any key
if self.facing_right:
self.x += 20
if self.facing_left:
self.x -= 20
self.dashing = True
Make sure that when you hit the ground it does self.dashing = False else you will be able to dash forever.
Just put this function in the player class if you are doing it OOP.
Else if you are not using classes, put it anywhere in the file and take out all self..
first time poster here, so I hope you guys can help me :)
I'm working on a project in which I want to play a game of SET. It all works (JEEJ), however I want to be able to use some sort of time function. This will do the following:
at start of game the time starts running
if x:
y
reset timer to zero
elif not x and time == 30:
do some action
I tried a lot of things; using time.time(), but this cannot be reset as far as I know; I found a few stopwatch like classes which I tried using, but they were slow (?); I tried perf_counter()... But now I'm at loss, so I hope any of you may know what to do...
Note that I want to "play" the game and do actions while the time runs...
Many thanks in advance!
There are a few ways to solve this problem. One is using time:
import time
timer_start = time.time()
if x:
y
timer_start = time.time()
if not x and time.time() >= timer_start + 30:
do some action
Note that I use >= because the time is highly unlikely to be exactly 30.0, better to fire it the first time after.
Another way is to use pygame.time.set_timer():
pygame.time.set_timer(pygame.USEREVENT, 30000) #milliseconds
# You cal also use USEREVENT+1, USEREVENT+2 etc. if you want multiple timers
if x:
pygame.time.set_timer(pygame.USEREVENT, 30000) #milliseconds
for event in pygame.event.get(): #merge this with your actual event loop
if event.type == pygame.USEREVENT:
if not x:
y
# reset the timer since it repeats by default
pygame.time.set_timer(pygame.USEREVENT, 0)
I'm building a game in python, and I want to create an event listener that checks for when the main character's hp is smaller or equal to 0, and then executes a game over function. In other languages (vb.net) i have achieved this by creating a new thread that continuously loops an if statement until the condition is met, then runs the game over code, then closes itself. How do you create/start/close threads in python? Also, is there a better way of doing this that is sitting right in front of me?
from threading import Thread
def my_function():
while True:
if player.lives < 5:
do_stuff()
Thread(my_function).start()
However most of the times the games are developed following a frame-loop rule, with the following structure:
def my_game():
should_continue = False
while should_continue:
should_continue = update_logic()
update_graphics()
What you define in update_logic and update_graphics is up to you and the graphic library you're using (since you're using text, your function would just print text in your console), but some examples of the logic would be like this:
def update_logic():
if player.lives < 5:
return False
# these are just examples, perhaps not valid in your game
player.xdirection = 0
player.ydirection = 0
player.speed = 0
player.hitting = False
if player.damage_received_timer > 0:
player.damage_received_timer -= 1
if right_key_pressed:
player.xdirection = 1
if left_key_pressed:
player.xdirection = -1
if up_key_pressed:
player.ydirection = -1
if down_key_pressed:
player.ydirection = +1
if player.ydirection or player.xdirection:
player.speed = 20
if space_key_pressed:
player.hitting = True
# bla bla bla more logic
return True
This does not make use of threads and using threads is most of the times a bad practice if multiple events occur. However in your text games, perhaps not so much elements are involved, so it's unlikely a race condition would occur. Be careful, however. I always prefer these loops instead of threads.
I have asked a question similar to this before, but this time it is a little different. To me, the following code should work.
import datetime
# run infinitly
while(True):
done = False
while(not done):
#
#main program
#
#stopping condition
if currenttime == '103000':
done = True
#continue with rest of program
However, it doesn't continue with the rest of the program when it hits 10:30:00am.
The following program I KNOW works (on a raspberry pi):
import datetime
done = False
while not done:
currenttime = datetime.datetime.now().strftime('%H%M%S')
if currenttime != '103000':
print currenttime
if currenttime == '103000':
done = True
print 'It is 10:30:00am, the program is done.'
It made logical sense to me what I did in that first example. Does anyone know why it won't exit that loop and continue with the rest?
If the main program takes a long time to run, currenttime could jump from 102958 to 103005. Therefore skipping 103000 entirely.
Maybe you need to set currenttime, before you check? Also, the if statement has to execute exactly at 103000 in order for done = True to execute.
while(True):
done = False
while(not done):
#
#main program
#
# need to set current time
currenttime = datetime.datetime.now().strftime('%H%M%S')
#stopping condition (use >= instead of just ==)
if currenttime >= '103000':
done = True
#continue with rest of program
Note that is not guaranteed that your loop has one iteration in each and every available second. The more load is on your system, the larger the likelihood that the loops skips a second, which potentially would be the termination criterion. There are also cases where seconds may be skipped, e.g. due to time synchronization or daylight saving issues.
Instead of a busy waiting loop, you could pre-compute the timedelta in seconds and then sleep for that many seconds.
Advantages:
You'll save computation power that other processes on your machine could use instead.
It probably increases the lifetime of your hardware.
This will also be more energy efficient.
Example:
import datetime
import time
def wait_until_datetime(target_datetime):
td = target_datetime - datetime.datetime.now()
seconds_to_sleep = td.total_seconds()
if seconds_to_sleep > 0:
time.sleep(seconds_to_sleep)
target_datetime = datetime.datetime(2025, 1, 1)
wait_until_datetime(target_datetime)
print "Happy New Year 2025!"
Note that this may still fail to produce the desired behavior due to arbitrary changes of the systems date and time settings. Probably it would be best to adopt a completely different strategy to execute a specific command at a specific time. Have you considered implementing the desired behavior using a cron job? (You could send a signal to the process and thereby issue it to cancel the loop...)
import datetime
done = False
while True:
currenttime = datetime.datetime.now().strftime('%H%M%S')
if currenttime >= '103000':
break
print currenttime
print 'It is 10:30:00am, the program is done.'
If you can't use break:
import datetime
done = False
while not done:
currenttime = datetime.datetime.now().strftime('%H%M%S')
if currenttime >= '103000':
done = True
else:
print currenttime
print 'It is 10:30:00am, the program is done.'
I am a high school programming student and I have a small question. I have been tasked with writing a simple game in Tkinter where an icicle falls from the ceiling and you have to avoid it with your mouse. Simple enough. However, I have hit an issue. Whenever I run a loop in a Tkinter application, it won't open. I've tried with a for loop that pauses every .5 seconds using time.sleep() and the window opens as soon as the loop finishes. Is there some special thing I need to do to make loops work in Tkinter?
from Tkinter import *
import time
import random
class App:
def __init__(self, parent):
self.frame = Frame(root, bg= '#1987DF', width=800, height=800)
self.frame.bind("<Motion>", self.motionevent)
self.frame.pack()
#self.run()
def randhex(self):
b = "#"
for i in range(1, 7):
a = random.randint(0, 15)
if a == 10:
a = "A"
elif a == 11:
a = "B"
elif a == 12:
a = "C"
elif a == 13:
a = "D"
elif a == 14:
a = "E"
elif a == 15:
a = "F"
b = b+str(a)
return b
def motionevent(self, event):
xpos, ypos, bg = event.x, event.y, self.randhex()
str1 = "X : %d Y : %d BG : %s" % (xpos, ypos, bg)
root.title(str1)
x,y, delta = 100, 100, 10
self.frame.config(bg=bg)
def run(self):
for i in range(0, 10):
time.sleep(.5)
print 'i'
self.frame.config(bg=self.randhex())
root = Tk()
app = App(root)
root.mainloop()
Currently all it is supposed to do is change the background when the mouse moves. When the line in init that says self.run() is uncommented it will print 'i' 10 times then the window will open. Help?
Writing an event based program is not the same as writing traditional programs. There is already an infinite loop running, and like any infinite loop, if you place another loop inside, the outer loop can't continue until the inner loop finishes. Since the outer loop is what causes the screen to refresh and events to be processed, inner loops effectively freeze your app until they are done.
Since there is already a loop running you don't need to create another loop. All you need to do is add little jobs to the event queue one at a time. Each job is, in effect, one iteration of your inner loop.
For example, if you wanted to write an inner loop like this:
for i in range(10):
print "i:", i
... you would instead add an event to the event queue and each time the event loop iterates (or more precisely, each time it finishes processing any other events) it will do one iteration of your loop. You do it like this:
def do_one_iteration(i):
print "i:", i
if i < 9:
root.after_idle(do_one_iteration, i+1)
Then, after the first time you call do_one_iteration, it will place the next iteration of itself on the event queue, and continue to do so until it decides it is done.
Typically you would call do_one_iteration when the user presses a button (eg: the "start" button). Call it once, then it does one bit of work (ie: moving the icicle down a couple of pixels) and then reschedules itself.
In game development you might have a function called update_display which is in charge of redrawing everything. It could, for example, subtract 1 from the Y coordinate of each icicle. You can add bindings for the left and right arrows to move the player (by incrementing or decrementing the X coordinate), and your update function would use these new coordinates to redraw the player.
By the way, you can slow down your program by using after instead of after_idle to call the function after a slight delay. This delay can be used to control the frame rate. For example, assuming the update is nearly instantaneous (and it probably will be in your case), calling after with an argument of 41 (milliseconds) yields a framerate of approximately 24 fps (24 frames times 41 milliseconds equals 984 milliseconds, or roughly 24 frames per second)
It may sound complicated but it's really pretty easy in practice once you do it once or twice.