That's not an error, as Kylotan points out. sys.exit() raises the SystemExit exception, which, since you don't handle it within your program, bubbles up to the operating system.
You have a couple of options. The first is to have a program-global flag indicating running status, which the QUIT exit handle sets to False:
running = Truedef input(events): for event in events: if event == QUIT: running = False ...while running: input(pygame.event.get())
This method works, of course, but it introduces an object with no ownership semantics, and thus no access controls - the global flag, running. A second approach avoids this pitfall, but complicates your main loop slightly:
def input(events): for event in events: if event == QUIT: sys.exit(0) ...while running: try: input(pygame.event.get()) except SystemExit: print "Good bye!" break
This method works, but now you're going to be instrumenting your main loop to handle all the various exceptions you may raise within your code for non-error purposes. Ugh. Plus, the exception mechanism is being used as a secondary event queue... hey, wait a minute!
The third approach is simply to use the event queue as the main loop:
NULL_EVENT = pygame.event.USEREVENT + 1evt = pygame.event.Event(NULL_EVENT, None)while evt.type != QUIT: ...
You can make this more robust by using another user-created event type as the loop sentinel, so that your application can respond to a QUIT event, perform some processing, then post your own loop exit event to the queue:
NULL_EVENT = pygame.event.USEREVENT + 1TERMINATE = pygame.event.USEREVENT + 2evt = pygame.event.Event(NULL_EVENT, None)while evt.type != TERMINATE: ... if evt.type == QUIT: # pause game and prompt user. if yes, # release resources, etc, then # pygame.event.post(pygame.event.Event(TERMINATE, None)) # ...
You can do a lot of very powerful things with the PyGame event system. You can maintain rock-solid frame updates and game heartbeat by generating corresponding events using a timer:
pygame.time.set_timer(NULL_EVENT, 1000.0/30) # generate a NULL_EVENT 30 times a second
By using pygame.event.set_blocked, pygame.event.set_allowed and pygame.event.get, you can event priority sort your events, such that screen refreshes, etc, are reliably handled on time. I'm looking into building a preemptive layer on top of this foundation, and I'll share what I find.