Hello I am building a simple mp3 player. I have it now so it plays a sound fine when I enable the function, but the gui temporarily freezes while waiting for the sound file to finish. I would like to be able to hit stop, exit, etc while the file plays. Any advice?
def Play():
soundfile = 'test.wav'
pygame.mixer.music.load(soundfile)
pygame.mixer.music.play(0)
events = pygame.event.get()
while pygame.mixer.music.get_busy():
for event in events:
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.Q:
sys.exit()
elif event.type == pygame.MOUSEMOTION:
print "mouse at (%d, %d)" % event.pos
When pygame.event.get() is not being called, the game window will freeze. Since you're calling pygame.event.get() outside of your while loop, the window event queue is only getting flushed once. The simple solution is to just replace the events variable with pygame.event.get() directly inline so that it gets called continuously while get_busy() returns true.
In general for these situations, a better solution would be a little refactoring where you have pygame.event.get() called once centrally in your program and instead of calling a function called Play() that handles managing your event queue, you instead have a function called handlePlayForOneFrame(list_of_relevant_events_this_frame).
Related
I'm working on a project and when I add the clock.tick to my main game loop, my pygame window doesnt close.
def game_loop():
"""The main game loop that runs as the game runs. Returns when the pygame window is closed."""
global running
global timer
while running:
while timer > screen.fixed_fps:
fixed_update()
timer -= screen.fixed_fps
update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
return
screen.clock.tick(screen.fps)
timer += delta_time()
pygame.quit()
return
When I click the X, the screen freezes until I let go, but unless I click the X in a very specific time frame( I usually need to click it 20 times to close) it doesnt work.
This is likely because of the way you are handling the QUIT event in your event loop. The pygame.event.get() function returns all of the events that have occurred since the last time it was called, so if there is a delay in your loop, the QUIT event may not be handled until multiple events have accumulated. To fix this, you should move the QUIT event handling code to the top of your event loop so that it is handled as soon as the event occurs. Also you could try to add pygame.display.update() after the event handling to make sure it is updated.
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
return
while timer > screen.fixed_fps:
fixed_update()
timer -= screen.fixed_fps
update()
screen.clock.tick(screen.fps)
timer += delta_time()
I'm only starting to grasp this idea of abstracting complex stuff via functions, so I decided to practice it a bit in Pygame.
So, this code right here works just fine, the pygame window is present, and you can close it by pressing X button:
#pygame initialization code and etc.
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#code for drawing stuff out
But let's say I want to make a function to just handle closing the window just for the sake of it:
#pygame initialization code and etc.
running = True
def handle_quit_event():
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
else:
return True
while running:
running = handle_quit_event()
#code for drawing stuff out
Now it doesn't work the same way anymore, the pygame window appears for a blink moment, and then program finishes, leaving me with this unease feeling that my idea of abstracting stuff using functions is all wrong.
[EDIT]: So in my code the function checks for only the first event in the list, but it still doesn't explain why the program finishes right after running it, because even if it checks for the first event, it still should return true by running else clause. So what am I missing?
Abstracting functionality into functions is a great idea! Unfortunately your re-write has introduced a bug that might be causing your broken game. Without a stacktrace or error messages, it's hard to say exactly why the game is broken.
Onto the bug:
The function handle_quit_event doesn't iterate through all the events in pygame.event.get(). It returns True or False after checking the first event.
You probably wanted to write it more like:
def handle_quit_event():
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
return True
A more pythonic approach that uses list-comprehension and any():
def handle_quit_event():
return not any([event.type == pygame.QUIT for event in pygame.event.get()])
Note the flipped logic with not is required because your function is currently returning True if there is not a QUIT event.
After a long time trying to install pygame for 2.7 it finally installs and I now have it downloaded, but there is now the problem that it keeps not responding after a couple seconds of being open. Any answer will be appreciated, the code that I have so far is just.
import pygame
pygame.init()
pygame.display.set_mode((640,480))
so I need some help please.
So what you want to do, like what skrx said, is a while loop to continuously keep the code inside the while loop and the pygame window running, and as well as a for event loop, in order to be able to shut down the window. Here's how you can do it:
import pygame
pygame.init()
pygame.display.set_mode((640, 480)) # opens the display
while True: # the while loop that will keep your display up and running!
for event in pygame.event.get(): # the for event loop, keeping track of events,
if event.type == pygame.QUIT: # and in this case, it will be keeping track of pygame.QUIT, which is the X or the top right
pygame.quit() # stops pygame
There are other ways of stopping the while loop, and you could do this:
running = True
while running: # the while loop that will keep your display up and running!
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
Hope this helps!
I was writing a function to make it easy to detect a key press without having to use the for loop that is normally used:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == key:
And I found that the function that I had written didn't work, and this is because I have this test_for_quit function in all my projects that runs every frame. I've found this to be useful as I can just copy this into any program that I'm writing:
def test_for_quit():
'''Shuts down the game if it's closed'''
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
Surprisingly this is the first game I've made since implementing that function to all my programs, that doesn't use key presses. But I found that the reason that the new function that I've written didn't work because pygame.event.get() had already been called in the test_for_quit function.
After some more testing I found that this method cannot be called twice, for instance:
while True:
print(pygame.event.get())
print() #Leaves an empty line
print(pygame.event.get())
returns:
[<Event(17-VideoExpose {})>, <Event(16-VideoResize {'h': 600, 'size': (800, 600), 'w': 800})>, <Event(1-ActiveEvent {'gain': 0, 'state': 1})>, <Event(4-MouseMotion {'rel': (538, 315), 'pos': (537, 314), 'buttons': (0, 0, 0)})>]
[]
So why is it that pygame.event.get() can only be called once, this really intrigues me and I couldn't find anything about it on the internet?
Also I've decided to not continue using the test_for_quit function and the key_down function in favour of just using the traditional for loop.
event.get can be called as many times as you want. The matter is it does take the events out of the event queue - and is up to your program to consume them. When it is called a second time with no interval (pygame itself knows nothing about "frames" - you give the delay between frames) - all events are gone, and no others have been generated.
The documentation for event.get reads:
This will get all the messages and remove them from the queue. If a type or sequence of types is given only those messages will be removed from the queue.
If you are only taking specific events from the queue, be aware that the queue could eventually fill up with the events you are not interested.
You have two choices: keep your "copy and pasted" call to event.get and read the keyboard state by using other calls - pygame.key.get_pressed for one - or to use a smarter way to consume the events in the queue.
There are even ways to check for evetns on the event queue without consuming them - so you could place those calls before a call to events.get.
One is that the function itself allows you to specify event types you are interested in. So let's suppose you have a function to deal with mouse events and a function to deal with keybard events:
def do_keys():
for event in pygame.event.get(KEYDOWN):
...
def do_mouse():
for event in pygame.event.get((MOUSEMOTION, MOUSEBUTTONDOWN)):
..
def main():
while True:
do_keys()
do_mouse()
# discard other events:
pygame.event.get()
# draw secreen
...
pygame.time.delay(...)
Or, which is even easier, you can simply assign the return value of the call to pygame.event.get to a variable - that will be a single list over which you can iterate as many times as you wish.
events = pygame.event.get()
for event in events():
# treat some evetns here
# some other logic here
...
do_keyboard_things(events)
def do_keyboard_things(events):
for event in events:
...
i am new to pygame and i was wondering what an event loop is and what clock does in this situation, like what is clock.tick(60)? I don't understand any explanations online
clock = pygame.time.Clock()
run = True
while run:
clock.tick(60)
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time.
That meas that the loop:
clock = pygame.time.Clock()
run = True
while run:
clock.tick(60)
runs 60 times per second.
for event in pygame.event.get() handles the internal events an retrieves a list of external events (the events are removed from the internal event queue).
If you press the close button of the window, than the causes the QUIT event and you'll get the event by for event in pygame.event.get(). See pygame.event for the different event types. e.g. KEYDOWN occurs once when a key is pressed.
e.g. The following loop prints the names of the a key once it it pressed:
run = True
while run:
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
print(pygame.key.name(event.key))