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 events 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 keyboard 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 screen
...
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 events here
# some other logic here
...
do_keyboard_things(events)
def do_keyboard_things(events):
for event in events:
...