Event handling

Event Handling

Events are fairly simple idea. We want our game to perform its tasks regardless of user input. Imagine game which force user to constantly move mouse in order to just work!
However it mean that user can interact at any given point with our game. When we are displaying main menu, when we are painting our next frame, or computing game logic.
In order to store user input for letter use, we will (or more precisely PyGame will) put them in containers which we will call Events. Each event store data specific to one type of event (like mouse button pressed, key down, etc), and for only one user generated input. So if user click on multiple keys, we will get multiple events. If user press 'B' multiple times, we will get multiple events, etc.

To enable event handling in our games we will create one class, that have python functions for every type of events, and one which will call them depending on the type of event.

Code

Save it as cevent.py.

import pygame
from pygame.locals import *
 
import pygame
from pygame.locals import *
 
class CEvent:
    def __init__(self):
        pass
    def on_input_focus(self):
        pass
    def on_input_blur(self):
        pass
    def on_key_down(self, event):
        pass
    def on_key_up(self, event):
        pass
    def on_mouse_focus(self):
        pass
    def on_mouse_blur(self):
        pass
    def on_mouse_move(self, event):
        pass
    def on_mouse_wheel(self, event):
        pass
    def on_lbutton_up(self, event):
        pass
    def on_lbutton_down(self, event):
        pass
    def on_rbutton_up(self, event):
        pass
    def on_rbutton_down(self, event):
        pass
    def on_mbutton_up(self, event):
        pass
    def on_mbutton_down(self, event):
        pass
    def on_minimize(self):
        pass
    def on_restore(self):
        pass
    def on_resize(self,event):
        pass
    def on_expose(self):
        pass
    def on_exit(self):
        pass
    def on_user(self,event):
        pass
    def on_joy_axis(self,event):
        pass
    def on_joybutton_up(self,event):
        pass
    def on_joybutton_down(self,event):
        pass
    def on_joy_hat(self,event):
        pass
    def on_joy_ball(self,event):
        pass
    def on_event(self, event):
    pass
 
if __name__ == "__main__" :
    event = CEvent()

Explanation

I think code is self-explanatory. I will say only that routines on_joy_* will be introduced in distinct tutorial if there will be demand for it. All others will be introduced through out this tutorials.

One to rule them all

So far we have lots of methods how to chain them all ? How to make one to rule them all ;) ?
Change on_event into following:

def on_event(self, event):
        if event.type == QUIT:
            self.on_exit()
 
        elif event.type >= USEREVENT:
            self.on_user(event)
 
        elif event.type == VIDEOEXPOSE:
            self.on_expose()
 
        elif event.type == VIDEORESIZE:
            self.on_resize(event)
 
        elif event.type == KEYUP:
            self.on_key_up(event)
 
        elif event.type == KEYDOWN:
            self.on_key_down(event)
 
        elif event.type == MOUSEMOTION:
            self.on_mouse_move(event)
 
        elif event.type == MOUSEBUTTONUP:
            if event.button == 0:
                self.on_lbutton_up(event)
            elif event.button == 1:
                self.on_mbutton_up(event)
            elif event.button == 2:
                self.on_rbutton_up(event)
 
        elif event.type == MOUSEBUTTONDOWN:
            if event.button == 0:
                self.on_lbutton_down(event)
            elif event.button == 1:
                self.on_mbutton_down(event)
            elif event.button == 2:
                self.on_rbutton_down(event)
 
        elif event.type == ACTIVEEVENT:
            if event.state == 1:
                if event.gain:
                    self.on_mouse_focus()
                else:
                    self.on_mouse_blur()
            elif event.state == 2:
                if event.gain:
                    self.on_input_focus()
                else:
                    self.on_input_blur()
            elif event.state == 4:
                if event.gain:
                    self.on_restore()
                else:
                    self.on_minimize()

Usage

Now that we have laid ground work, we can use it!

CApp should inherit after CEvent, so all functions in CEvent are available in CApp.
Then we just need to change event handling functions we need to.

Here is simple example which will use our new event handling code to handle exit event:

#add in import section
import cevent
# change CApp into
class CApp(cevent.CEvent):
#...
 
#... delete on_event(): !!!!!!!!!!
 
#add on_exit(self) to CApp:
def on_exit(self):
    self._running = False

Now our code is a bit tricky! Python will not find on_event in App, so it will use it's parent's class (CEvent) method on_event. But on_event will call on_exit from App class!
How CEvent can know about our on_exit() function in App class? I can not!

How ever we have told python that App is inheriting after CEvent, so Python will do few things for us:

  • will provide every method from CEvent as if they where App's own methods (just like with on_event)
  • will make sure that methods defined in App will be preferred over CEvent methods (just like with on_exit)

Professional programmers call this pattern "Template method". Because if you look at what we have done, then you will realize that our on_event function is template, with places (like on_exit) that can be changed letter.

Zipped Source Code:

Full events example

Add a New Comment