PyGame – Event Handling
Introduction
To continue further into my PyGame exploration articles and tutorials, I’ll try to come up with a complete Shmup game as example. I already covered Animated sprites and Parallax Scrolling in 2D games as a start you can look at the PyGame tutorials list page to see them all.
The goal of this article is to combine what we have already learned into a single piece and add a new feature. For instance, this application will be featuring parallax background, animated sprites and we will add user inputs handling using PyGame’s events management.
Credits
As usual, I like to deserve credit where it’s due. I’d like to thank the following artists for their awesome work :
- Clouds Brushes by ~JavierZhX
- Fighter by ~PrinzEugn
Class evolution – The Fighter
Like Parallax class inherited from our base AnimatedSprite class in the previous article, we will create a new Fighter class (inheriting from AnimatedSprite class) and add specific members to handle it’s particular behaviors.
Let’s see some code first, I’ll go into explaining it just after.
class Fighter(AnimatedSprite):
def __init__(self, images, fps = 60):
AnimatedSprite.__init__(self, images, fps)
self.speed = 600.
self.default_speed = self.speed
self.location = (100, RESOLUTION[1]/2)
self.destination = self.location
self.stoping = False
'''
The higher self.slowing_factor is,
the longer it takes to stop a movement
'''
self.slowing_factor = 10.
# Forward movement image - default
self.image = self._images[1]
def event_handler(self, event):
if event.type == KEYUP:
self.stop(event.key)
if event.type == KEYDOWN:
self.move(pygame.key.name(event.key))
def update(self, t):
# Slowing effect
if self.stoping is True:
self.speed -= self.speed/self.slowing_factor
if self.stoping is False:
self.speed = self.default_speed
# Overriden to make use differently of the image's slices
def move(self, direction):
self.stoping = False
W,H = RESOLUTION - self.image.get_size()
x,y = self.location
if direction == 'up':
self.image = self._images[0]
self.destination = Vector2(x, 0)
elif direction == 'down':
self.image = self._images[2]
self.destination = Vector2(x, H)
elif direction == 'left':
self.destination = Vector2(0, y)
elif direction == 'right':
self.destination = Vector2(W, y)
def stop(self, key):
self.stoping = True
W , H = RESOLUTION - self.image.get_size()
x , y = self.destination
xa, ya = self.location
w , h = self.image.get_size()
self.image = self._images[1]
# Stopping Y Axis Movements
if key == K_UP:
self.destination = Vector2(x, max(ya-h*self.slowing_factor, 0))
if key == K_DOWN:
self.destination = Vector2(x, min(ya+h*self.slowing_factor, H))
# Stopping X Axis Movements
if key == K_LEFT:
self.destination = Vector2(max(xa-w*self.slowing_factor, 0), y)
if key == K_RIGHT:
self.destination = Vector2(min(xa+w*self.slowing_factor, W), y)
New Members
- stoping (boolean) is used to know at update time if we are, err, in the process of stoping our movement, wee need to be aware of this information to trigger a slowing down effect.
- slowing_factor (float) determines the ship’s inertia, the higher inertia is, the longer it takes to stop a movement.
- default_speed (float) is used to keep track of the original sprite’s speed and restore it when arrived to destination.
New Methods
event_handler method will make calls to appropriate method depending on the PyGame Event it received.
def event_handler(self, event):
if event.type == KEYUP:
self.stop(event.key)
if event.type == KEYDOWN:
self.move(pygame.key.name(event.key))
The move method simply changes the destination of our fighter sprite according to the keyboards keys inputs it receives. Eventually, it also changes the fighter’s image to an inclined version of it when moving lateraly (since we are running from left to right in this game, the lateral moves are Up and Down arrows).
def move(self, direction):
self.stoping = False
W,H = RESOLUTION - self.image.get_size()
x,y = self.location
if direction == 'up':
self.image = self._images[0]
self.destination = Vector2(x,0)
elif direction == 'down':
self.image = self._images[2]
self.destination = Vector2(x,H)
elif direction == 'left':
self.destination = Vector2(0,y)
elif direction == 'right':
self.destination = Vector2(W,y)
The stop method stops the sprite’s movement according to keys releases and restore the default sprite image. To avoid the sprite’s getting off the screen, we need to limit the coordinates to values comprised into (RESOLUTION – sprite’s image size).
def stop(self, key):
self.stoping = True
W , H = RESOLUTION - self.image.get_size()
x , y = self.destination
xa, ya = self.location
w , h = self.image.get_size()
self.image = self._images[1]
# Stopping Y Axis Movements
if key == K_UP:
self.destination = Vector2(x, max(ya-h*self.slowing_factor, 0))
if key == K_DOWN:
self.destination = Vector2(x, min(ya+h*self.slowing_factor, H))
# Stopping X Axis Movements
if key == K_LEFT:
self.destination = Vector2(max(xa-w*self.slowing_factor, 0), y)
if key == K_RIGHT:
self.destination = Vector2(min(xa+w*self.slowing_factor, W), y)
Overriden Methods
The update method will be used to apply the slow down effect on movement stops.
def update(self, t):
# Slowing effect
if self.stoping is True:
self.speed -= self.speed/self.slowing_factor
if self.stoping is False:
self.speed = self.default_speed
Instantiating Entities
Let’s append a new instance of the Fighter class to the main loop to have it being updated, processed and rendered with other entities.
... fghtr = Fighter(fighter, 60) elements.append(fghtr) ...
Since other objects doesn’t need to handle Events, we’ll only add the fighter’s event handling method call to the events polling loop.
for event in pygame.event.get():
fghtr.event_handler(event)
This way, our sprite will be able to receive input from player and it’s location, destination and image will be accordingly updated and rendered.
Source and Ressources
The PyGame application is available for download here :
Dependencies:
Screenshot & Conclusion
That’s what’s closes this article. I hope it has been helpful in anyway to you. Provided code is not perfect at all and not optimized because like you eventually, I’m still learning ;)
In the next article I’m planning to cover Fighter’s firing abilities aka, bullet hell. Stay tuned!
def __init__(self, images, fps = 60):
AnimatedSprite.__init__(self, images, fps)
self.speed = 600.
self.default_speed = self.speed
self.location = (100, RESOLUTION[1]/2)
self.destination = self.location
self.stoping = False
”’
The higher self.slowing_factor is,
the longer it takes to stop a movement
”’
self.slowing_factor = 10.
# Forward movement image – default
self.image = self._images[1]
def event_handler(self, event):
if event.type == KEYUP:
pygame.event.pump()
pressed_keys = pygame.key.get_pressed()
if 1 not in pressed_keys:
self.stop(event.key)
if event.type == KEYDOWN:
self.move(pygame.key.name(event.key))
def update(self, t):
# Slowing effect
if self.stoping is True:
self.speed -= self.speed/self.slowing_factor
if self.stoping is False:
self.speed = self.default_speed
def move(self, direction):
# Overriden to make use differently of the image’s slices
self.stoping = False
W,H = RESOLUTION – self.image.get_size()
x,y = self.location
if direction == ‘up’:
self.image = self._images[0]
self.destination = Vector2(x,0)
elif direction == ‘down’:
self.image = self._images[2]
self.destination = Vector2(x,H)
elif direction == ‘left’:
self.destination = Vector2(0,y)
elif direction == ‘right’:
self.destination = Vector2(W,y)
def stop(self, key):
self.stoping = True
W,H = RESOLUTION – self.image.get_size()
x, y = self.destination
xa,ya = self.location
w,h = self.image.get_size()
self.image = self._images[1]
# Stopping Y Axis Movements
if key == K_UP:
self.destination = Vector2(x, max(ya-h*self.slowing_factor, 0))
if key == K_DOWN:
self.destination = Vector2(x, min(ya+h*self.slowing_factor, H))
# Stopping X Axis Movements
if key == K_LEFT:
self.destination = Vector2(max(xa-w*self.slowing_factor, 0), y)
if key == K_RIGHT:
self.destination = Vector2(min(xa+w*self.slowing_factor, W), y)











Reddit/p: PyGame Event Handling Basics http://bit.ly/NOBCD
This comment was originally posted on Twitter
Shiny Blog » PyGame – Event Handling http://bit.ly/19fm5H
This comment was originally posted on Twitter
I’m just sharing back knowledge to the community. Hope this helps.
This comment was originally posted on Reddit
When I’ve done larger projects with PyGame it seems a good idea to separate the event handling to its own module and make the different actions triggerable by callbacks. Haven’t really found other ways to modularize the event handling routines. Different game states, different keyboard layouts, writing normal text. All those require some sort of an interface that’s beyond a simple game implementation.
This comment was originally posted on Reddit
Thanks for your advice! It might help for future conceptions. Speaking of modularization, what about an interface that wraps all the keyboards inputs and layout management triggerring only custom events to the main application? Is this would be a good implementation?
This comment was originally posted on Reddit
That’s exactly what I do, I wrote a simple little engine that binds to pygame, and the events portion handles default stuff; for example, sending events to the menu / console if it’s open, next to the game itself if not, etc.
This comment was originally posted on Reddit
Hey, thanks! What’s your opinion on pyglet vs pygame?
This comment was originally posted on Reddit
You know I’m just started learning Python and PyGame. I never heard about PyGlet Before so I don’t have any opinion about it.
This comment was originally posted on Reddit
Doesn’t it generate an overhead work concerning the mapping between raw and custom events ?
This comment was originally posted on Reddit
Hm. I’m a little worried that perhaps you don’t know enough Python to know good coding practices, etc. It’s a really nice thing that you’re trying to help people, but are you sure it’s the best time to make Pygame tutorials when you’ve just started learning Python and Pygame?
This comment was originally posted on Reddit
It’s just a few extra comparisons per mouse/keyboard event. Put your `if self.consoleOpen == True then` at the top of the loop.
This comment was originally posted on Reddit
Although I might just be started with Python, I still have a strong background and more than 10 years experience in programming and OOP. That will not prevent me or anyone else to make mistakes, but it helps at not making too big ones.
This comment was originally posted on Reddit
Shut the fuck up hater
This comment was originally posted on Reddit
It’s a fair question, but writing tutorials for other people can be a great way to organize and expand on your knowledge. You can always go back and improve the tutorial later. I do that all the time.
This comment was originally posted on Reddit
Thanks for this. I’m helping my 11yo son learn programming through python/pygame. I’m also learning the language with him since I didn’t know python yet, so it helps having more tutorials explaining really basic things.
This comment was originally posted on Reddit
I’m sure your doing it well with your son :) Nonetheless, I recently heard about [Hello World!](http://www.manning.com/sande/), It’s a book to help kids learn programming and it’s Python centered, did you know about it ?
This comment was originally posted on Reddit
This is one of the reasons I’m looking at [LÖVE](http://love2d.org/?page=tutorial&id=002) instead of PyGame for my simple game programming needs. I was bummed by having to do this wrapping, but to be fair, PyGame is more of a game library than a game engine.
This comment was originally posted on Reddit
BTW, If you found any misconception or if you know better coding practices that relates to subjects covered my tutorials, I’m totally open to your feedback.
This comment was originally posted on Reddit
100% agree. In my understanding, PyGame is more the SDL bindings for Python than anything else.
This comment was originally posted on Reddit
Yep PyGame is just a wrapper around SDL That does mean the experience comes over if you decide to roll your own project, you’ve got a general idea of what to expect binding to SDL. EDIT: and thanks for the link, that is awesome. Will investigate further.
This comment was originally posted on Reddit
Hey, that looks like a good book. It reminds me of my first book, when I was 9 – *Your first BASIC program*. It had cute cartoons of snaky-looking things (I think they represented contiguous memory or something), and accessible first projects. A few years ago, when I was thinking of teaching my kids programming, I looked around, and was saddened by the dearth of self-teaching materials for that age range. My son is doing ok through reading other people’s programs, and using the pygame documentation, but he relies very heavily on me to explain things and help him debug. His programs have just gotten complex enough that he’s suffering from the poor organization and misuse of lists that he started with. :) Time to teach some program design, I think. He’s started playing with the Python Challenge, too, which is a good introduction to algorithms and some of the more interesting python library functions.
This comment was originally posted on Reddit
When he is learning is probably the only time he’ll be motivated enough to write a tutorial for free.
This comment was originally posted on Reddit
I’m interested in knowing your arguments for this assumption.
This comment was originally posted on Reddit