Creating a Game in Python Using PyGame – Part 3 – Adding the bad guys

All right in this section of the tutorial we are going to start adding the bad guys. If you are familiar with the changes that we made in part two it should be pretty clear to you how are are going to create these bad guys. If you haven’t already you should check out part one and part two. If you would like the full source and all of the images you can get it here.

First we are going have to create a new class based on our basicSprite class. I created a new file called and inside of that I created a class called Monster:

[code lang=”python”]
class Monster(basicSprite.Sprite):

For now we’re not going to go too crazy in our enemy AI, we’re just going to get them to choose a random direction to move and move in that direction until they hit a wall. We’ll also add in another option where after a certain amount of moves the monster will choose another random direction. This is just to add a little but more randomness into the Monster, it’s not really what we’d like to use at the end of the day but it works out all right.

Now we’ll take a look at the Monsters __init__ function:

[code lang=”python”]
def __init__(self, centerPoint, image, scared_image=None):

basicSprite.Sprite.__init__(self, centerPoint, image)
“””Save the original rect”””
self.original_rect = pygame.Rect(self.rect)
self.normal_image = image
if scared_image !=None:
self.scared_image = scared_image
self.scared_image = image

self.scared = False
“””Initialize the direction”””
self.direction = random.randint(1,4)
self.dist = 3
self.moves = random.randint(100,200)
self.moveCount = 0;

You can see that there is a bit more happening here then there is in out basic sprites. The first thing you’ll notice is the fact that the Monster is going to have two images, a normal image and a scared image. The scared image is what we will be drawn as the monster when the snake is in it’s “super” state, which is caused when it eats a super pellet.

You’ll also notice that we save a copy of the original rect, the reason that we do this is because that is where the Monster will go if it has been eaten by the snake. This probably isn’t how we will want to handle it in the end, but it’s a pretty good start.

Then we start laying out the Monster AI, the first thing to do is choose an initial direction:

[code lang=”python”]
self.direction = random.randint(1,4)

The direction is simply a random integer between 1 and 4, each integer being a direction from the Monster to travel in (1=left, 2=up, 3=right, and 4=down) the monster will then travel self.dist pixels every-time it is updated until it hits a wall, at which point it will choose another random direction.

After that we initialize the idea of moves and moveCount, this is the second degree of randomness that we add into the Monster. The idea is that after 100-200 moves the Monster will choose another random direction.

If you’ve read part 2 of this PyGame series the structure of our Monsters update function should come as no surprise:

[code lang=”python”]
def update(self,block_group):
“””Called when the Monster sprit should update itself”””
xMove,yMove = 0,0

if self.direction==1:
xMove = -self.dist
elif self.direction==2:
yMove = -self.dist
elif self.direction==3:
xMove = self.dist
elif self.direction==4:
yMove = self.dist

self.rect.move_ip(xMove,yMove) #Move the Rect
self.moveCount += 1 #Update the Move count

if pygame.sprite.spritecollideany(self, block_group):
“””IF we hit a block, don’t move – reverse the movement”””
self.direction = random.randint(1,4)
elif self.moves == self.moveCount:
“””If we have moved enough, choose a new direction”””
self.direction = random.randint(1,4)
self.moves = random.randint(100,200)
self.moveCount = 0;

The next thing that we are going to create is a function that will let us set the Monsters scared state:

[code lang=”python”]
def SetScared(self, scared):
“””Tell the monster to be scared or not”””
“””Should we update out scared image?”””
if self.scared != scared:
self.scared = scared
if scared:
self.image = self.scared_image
self.image = self.normal_image

This function is pretty self-explanatory, we just set the current state and the current image for the monster based on that state.

The next function that we need is a “eaten” function, this is the function that will be called when the monster has been eaten by the snake. This function is, again, very simply and simply moves the monster back to it’s original position and resets its state:

[code lang=”python”]
def Eaten(self):
“””Well looks like we’ve been eaten!, reset to the original
position and stop being scared”””
self.rect = self.original_rect
self.scared = False
self.image = self.normal_image

The next thing that we need to do is make sure that the snakes update function takes into account these new monsters:

[code lang=”python”]
def update(self,block_group,pellet_group,super_pellet_group,monster_group):
“””Called when the Snake sprit should update itself”””

if (self.xMove==0)and(self.yMove==0):
“””If we arn’te moving just get out of here”””
“””All right we must be moving!”””

if pygame.sprite.spritecollideany(self, block_group):
“””IF we hit a block, don’t move – reverse the movement”””

“””Check to see if we hit a Monster!”””
lst_monsters =pygame.sprite.spritecollide(self, monster_group, False)
if (len(lst_monsters)>0):
“””Allright we have hit a Monster!”””
“””Alright we did move, so check collisions”””
“””Check for a snake collision/pellet collision”””
lstCols = pygame.sprite.spritecollide(self
, pellet_group
, True)
if (len(lstCols)>0):
“””Update the amount of pellets eaten”””
self.pellets += len(lstCols)
“””if we didn’t hit a pellet, maybe we hit a SUper Pellet?”””
elif (len(pygame.sprite.spritecollide(self, super_pellet_group, True))>0):
“””We have collided with a super pellet! Time to become Super!”””
self.superState = True,{}))
“””Start a timer to figure out when the super state ends”””

You’ll notice that this function is relatively similar to what happened in part 2, except that some of the code has been moved here, and we now check to see if we have collided with any monsters.

The first thing we check is if we have collided with a wall, if so we reverse our movement, so that the snake doesn’t move. Instead of leaving the function, we continue to test to see if the snake has hit a monster. If the snake has hit a monster we call the MonsterCollide function to see what should happen. If no monster was hit we then check to see if any pellets or super pellets were hit.

If the snake eats a super pellet, we set its state to be super, then we post an event to our main loop telling it that the snake has become super, and then we start a three second time. The three second timer is basically how long the snake will stay in it’s super state and be able to eat monsters.

The MonsterCollide function is detailed below:

[code lang=”python”]
def MonsterCollide(self, lstMonsters):
“””This Function is called when the snake collides with the a Monster
lstMonsters is a list of Monster sprites that it has hit.”””

if (len(lstMonsters)< =0): """If the list is empty, just get out of here""" return """Loop through the monsters and see what should happen""" for monster in lstMonsters: if (monster.scared): monster.Eaten() else: """Looks like we're dead""",{})) [/code] The MonsterCollide function is relatively simple, It loops trough the list of monsters that the snake has collided with and decides what to do with each of them. If the monster is scared it gets eaten, and if the monster is not scared then we post the snake eaten even. No we need to look at the changes that we need to make to the LoadSprites function in the file. The only think that we are going to change is add the code to load the monsters, it will be identical to the code that we use to load the other sprites, except that monsters have a normal and scared image, and we will also switch to using RenderUpdates for our pygame groups, RenderUpdates are just like normal PyGame sprite groups except that they keep track of the rects that they have drawn to. So when you call RenderUpdates.Draw it will draw all of the sprites in the groups and then return a list of “dirty” rects. You then take the list of rects and pass it into pygame.display.update.

This way you save time by only redrawing only those sections of the screen that have changed.

The next changes that we need to make are in the MainLoop function. The first thing we have to do is pay attention to the events and timers that we have created in out other code.

[code lang=”python”]
elif event.type == SUPER_STATE_OVER:
self.snake.superState = False
“””Stop the timer”””
for monster in self.monster_sprites.sprites():
elif event.type == SUPER_STATE_START:
for monster in self.monster_sprites.sprites():
elif event.type == SNAKE_EATEN:
“””The snake is dead!”””
“””For now kist quit”””

Handling these events is pretty straight forward, the only one that will eventually change is the SNAKE_EATEN event. For now we just quite the game but in the future we will use up lives and things like that.

The next, and final change for this tutorial is the section of the code where we actually draw the sprites. As detailed above we are using RenderUpdate groups this time instead of the normal groups that we have used in the past. As a result our drawing code has to change slightly in order to pay attention to the rects that we have dirtied:

[code lang=”python”]
“””Do the Drawing”””
textpos = 0
self.screen.blit(self.background, (0, 0))
if pygame.font:
font = pygame.font.Font(None, 36)
text = font.render(“Pellets %s” % self.snake.pellets
, 1, (255, 0, 0))
textpos = text.get_rect(centerx=self.background.get_width()/2)
self.screen.blit(text, textpos)

reclist = [textpos]
reclist += self.pellet_sprites.draw(self.screen)
reclist += self.super_pellet_sprites.draw(self.screen)
reclist += self.snake_sprites.draw(self.screen)
reclist += self.monster_sprites.draw(self.screen)
“””Now Update the Display”””

As you can see not much has actually changed except for the fact that we are now paying attention to the rectangles that we have dirtied and are only updating those rather then redrawing the entire screen.

If you would like the full source of this tutorial, you can get it here.

Well that’s it for this tutorial, sorry it’s been such a long time coming, it seems that real life got in the way of my learning python. Hopefully I will get back on my schedule of updating this site once a week soon.

44 thoughts on “Creating a Game in Python Using PyGame – Part 3 – Adding the bad guys”

  1. Hey that’s really cool! I’m hoping to go back to the PyGame tutorials soon. I really enjoyed working on them when I did!

  2. first of all, this tutorial is very helpfull, great work!
    I have noticed that if u dont move the snake (i.e. u dont press any key), u’ll never hit a monster.

  3. Hi Gmac,

    Thanks for the information, I’m looking into writing a new PyGame tutorial so when I do I’ll be sure to fix that problem.

  4. Hi, I really liked this series of tutorials, and this website itself is such a great resource.

    Keep up the great work.

  5. Great tutorial — just working through it and am really turned on to Pygame thanks to it.

    One question though — I’m trying to find where SUPER_STATE_OVER gets defined since I’m getting an error that it isn’t. I haven’t been able to find it in the posted examples and am looking for a good place to put it. Thoughts?

  6. I’m glad you found your answer James. If anyone else has a similar problem SUPER_STATE is defined as follows near the top of

    [CODE lang=”python”]

  7. This is really well done! Thank you very much!
    On my machine (1GHz AMD Athlon) it runs way too fast.
    So I added the pygame.time lines to make it playable.

    50 pygame.display.flip()
    51 #################################################
    52 self.clock = pygame.time.Clock()
    53 #################################################
    54 while 1:
    56 #################################################
    57 self.clock.tick(30)
    58 #################################################
    59 self.snake_sprites.clear(self.screen,self.background)
    60 self.monster_sprites.clear(self.screen,self.background)

  8. I noticed when you kill a monster twice, it doesn’t respawn in its original space the second time. Nice game and tutorial! Thank you

  9. can you please help with the idea of creating a reflex action using pacman to eat all the food in the pellet and yet don.t get beaten by the ghost, say two ghost. I would need your assistance in python.

    Thanks sire!

  10. Can I just say what a comfort to discover a person that actually
    knows what they are talking about on the net.

    You certainly know how to bring a problem to light and make it important.

    More people have to read this and understand this side of
    your story. It’s surprising you aren’t more popular given that you certainly have the gift.

  11. By Zar May 16, 2013 – 4:12 amUse Torrent sites.First Download a Torrent downloaderdownload files / games from troernt sites.Read the comments because some of the troernts are hoax.Most of the software in the troernt sites has patches/serial/keygens or other software piracy tools. Download and use them at your own risk =’)

  12. This book will be one of many steps of world domination. First learn pyhotn (already done), Second take data that no one likes and turn it into pretty pictures (aided by the book), Third in the midst of my graphs and analysis I will come up with conclusive proof that me running the world would make things a better place. Mathematiclly the logic will be flawless. The plan will be simple yet genius, and it will all start from this book. (Tear)Seriously, I’m a Com Sci geek who just wants to shore up my graphic skills with some practical data and analytic know how. Ruling the world meh, don’t want the headache =)

  13. table workstation can supply you with entertainment, productivity and user friendly set up.Forget approximately long messy cords and also mouse pads.Easy to navigate just by using your own fingers, today’s laptop computer models need around their regular batteries or even an outlet to attach to his or her AC adapter also, you are all set.
    Using music, winning contests, watching video clips, or making a paper hasn’t been less difficult.Laptop perstable workstation can supply you with entertainment, productivity and user friendly set up.Forget approximately long messy cords and also mouse pads.Easy to navigate just by using your own fingers, today’s laptop computer models need around their regular batteries or even an outlet to attach to his or her AC adapter also, you are all set.

    Using music, winning contests, watching video clips, or making a paper hasn’t been less difficult.Laptop personal computers allow youngsters to deal with their each day busy schedules instead of loosing dedication.Some models offer screens that will be only visible on the person that seats precisely across these folks, eliminating it is likely that one having the capacity to visibly connection your documents and directories.Headphones along with microphones, as used in combination with desktop publishers are widely-used to offer an efficient nevertheless considerate practical experience.Keep on your mind that lots of the available models have software software already in place making The web browsing or implementing a job a quick and simple process of starting out the model.Finally, since notebook compters have turn into a mainstream system, many reasonable models can be obtained in electronic superstores or can be purchased to often be ordered directly from laptops manufacturers’ ?nternet sites.

  14. Raspberry Chocolate Truffle (custom blend at 70 calories for 4 oz.
    Then for each size, report any of an astounding array of toppings or goodies
    you want added (. If calories are a worry, then you
    can use sugar-free candy.

  15. Right here is the perfect webpage for everyone who wishes to
    find out about this topic. You know a whole lot its almost hard to argue
    with you (not that I really will need to…HaHa).

    You certainly put a fresh spin on a subject which
    has been written about for many years. Excellent
    stuff, just great!

  16. Have you ever thought about publishing an ebook or guest authoring
    on other websites? I have a blog centered on the same information you discuss and
    would love to have you share some stories/information. I know
    my visitors would enjoy your work. If you are even remotely interested,
    feel free to shoot me an e mail.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>