Pandadeath
  • Home
  • Projects
    • Rio Demo
    • Physics Otome
    • Penda >
      • Part 1
      • Part 2
      • Page 3
      • Part 4
      • Part 5
    • Anne's Book >
      • Prologue
      • Chapter 1
      • Chapter 2
      • Chapter 3
      • Chapter 4
      • Chapter 5
      • Chapter 6
      • Chapter 7
      • Chapter 8
      • Chapter 9
      • Chapter 10
      • Chapter 11
      • Chapter 12
    • Computer Theory >
      • Counting Systems
      • Logic
      • Stacks
    • Nintendo DS Lite
    • physics calculators >
      • Snell's Law
    • Programming Pacman in Python >
      • Level 0
      • Level 1
      • Level 2
      • Level 3
      • Level 4
      • Level 5
      • Level6
      • Level7
      • Level8
      • Level9
      • Level10
      • Level11
      • Level12
      • Level13
      • Level14
      • Level15
    • Laser Tag >
      • Simple laser receiver
      • More Complicated Laser Receiver
  • Math Stuff
    • Vectors
  • Comics
  • Blogs
    • Food Douche
    • Her Blog
    • Bubble Bobble Babble
  • Videos
    • Let's Play >
      • Arcade >
        • Twinkle Star Sprites
        • Aliens Gameplay
        • Gururin
        • Truxton score attempt 1
        • Waku Waku 7
  • About
  • Contact

Level 14 - Adding the Other Ghosts Back in

We got everything working well for Blinky.  We've accounted for every situation he could possibly be in, all we need to do now is to do the same thing for the other ghosts.  
Before we start adding in the other ghosts, however, lets make the GhostController object iterable.  The reason is because we're going to be writing a lot of the same code for the ghosts.  Instead of rewriting the code, if we make the object iterable, then we can just iterate over all of the ghosts since they all do the same thing anyways.  That way we can add as many ghosts as we want without doing much work.  We would just add it to the list we want to iterate over.  
In the GhostController we're going to add a ghostList list.  We then call the createGhosts method which will just add the ghosts to this list.

In order to make this object iterable, we'll add the __iter__ method, which just iterates over the ghostList. 
def __init__(self, nodes):
        self.ghostList = []
        self.createGhosts()

def __iter__(self):
        return iter(self.ghostList)

Here's a good example.  We change the render method so that we just iterate through all of the ghosts.  We can add as many ghosts as we want, and this will stay the same.  This will work for 2 ghosts or 100 ghosts.  
 def render(self, screen):
        for ghost in self:
            ghost.render(screen)

This makes it easier when setting the Point of Interest for all of the ghosts.  We just iterate through self and all of the ghosts in ghostList will get their update point of interest.  Notice that in the classes for each of the four ghosts I added a self.name variable which contains their name "BLINKY", "PINKY", "INKY", or "CLYDE".  That just makes it easier to check if we have the correct ghost when we're iterating.  In this case Inky needs to pass in pacman and blinky to determine his chase point of interest.  The other ghosts just need pacman.
def pointOfInterest(self, pacman):
        for ghost in self:
            if ghost.mode.name == "SCATTER":
                ghost.setScatterPOI()
            elif ghost.mode.name == "CHASE":
                if ghost.name == "INKY":
                    ghost.setChasePOI(pacman, self.getGhost("BLINKY"))
                else:
                    ghost.setChasePOI(pacman)
            elif ghost.mode.name == "FREIGHT":
                ghost.chooseRandomDirection = True
            elif ghost.mode.name == "SPAWN":
                ghost.setSpawnPOI()

We'll add this method which allows us to just pass in the name of the ghost we want, and we'll get the ghosts object back.  It just loops through the ghostList and finds the one with the matching name.
 def getGhost(self, name):
        for ghost in self:
            if ghost.name == name:
                return ghost

We change the modeUpdate method to take advantage of our changes.  Instead of writing one for each ghost, we just write it once and iterate over the ghosts.  Notice I also placed the powerPelletEaten = False at the end of the for loop since we don't want to set it to False, if it happens to be True, until we iterate over all of the ghosts.
def modeUpdate(self, timePassed):
        '''Transition mode'''
        for ghost in self:
            ghost.modeTimer += timePassed

            if ghost.mode.timeLimit:
                if ghost.modeTimer >= ghost.mode.time:
                    ghost.mode = ghost.modeStack.pop()
                    ghost.modeTimer = 0
                    ghost.reverseDirection()

            if self.powerPelletEaten:
                if ghost.mode.name != "SPAWN":
                    if ghost.mode.name != "FREIGHT":
                        dt = ghost.mode.time - ghost.modeTimer
                        tempNode = Mode(dt, True, ghost.mode.name)
                        ghost.modeStack.push(tempNode)
                        ghost.mode = Mode(7, True, "FREIGHT", 50)
                    ghost.modeTimer = 0
                    ghost.reverseDirection()

            if ghost.spawn:
                ghost.mode = Mode(name="SPAWN", speed=150)
                ghost.spawn = False
                ghost.modeTimer = 0
                ghost.setStartPath()

        self.powerPelletEaten = False

Then all we have to do is change the update method like so.
def update(self, timePassed, pacman):
        self.modeUpdate(timePassed)
        self.pointOfInterest(pacman)

        for ghost in self:
            ghost.update(timePassed)

Now we just simply have to add all of the ghost objects to the ghostList, and we now have four ghosts on the screen acting in their own unique way.  
def createGhosts(self):
        self.ghostList.append(Blinky(self.nodes))
        self.ghostList.append(Pinky(self.nodes))
        self.ghostList.append(Inky(self.nodes))
        self.ghostList.append(Clyde(self.nodes))
        for ghost in self:
            ghost.modeStack = self.setupModeStack()
            ghost.mode = ghost.modeStack.pop()

For Inky and Clyde we need to put this back in so that they know when to leave home.  
def leaveHome(self, validDirections):
        if self.captured:
            validDirections = self.node.filterLeftRight(validDirections)
            if self.readyToLeave:
                if self.node == self.homeNode:
                    self.setStartPath()
                    self.readyToLeave = False
                    self.leavingHome = True
            if self.leavingHome:
                if not self.startPath.isEmpty():
                    validDirections = []
                    validDirections.append(self.startPath.pop())
                    if self.startPath.isEmpty():
                        self.captured = False
                        self.leavingHome = False
                        self.readyToLeave = False

In the game loop we add this back in.  Inky can leave home when Pacman eats 30 pellets, and Clyde can leave home when Pacman eats 60 pellets.  I created a new class in the GhostController called leaveHome since only the GhostController knows each ghost individually.
​if pacman.pelletsEaten >= 60:
            ghosts.leaveHome("CLYDE")
        elif pacman.pelletsEaten >= 30:
            ghosts.leaveHome("INKY")

Here's the leaveHome method in the GhostController.  It just sets the ghosts readyToLeave variable to True.  
def leaveHome(self, name):
        for ghost in self:
            if ghost.name == name:
                ghost.readyToLeave = True

At this point we have the ghosts working and behaving just as we want them.  I changed the nodes and paths to white because it was hard to see Blinky.  We almost have a game that we can play!  That's exciting isn't it?  This hasn't been that hard, right?  I'm sure that I left a lot out, so if you can't get yours working, below is the code up to this point.  What do we want to do next?  Well, right now Pacman is invincible.  That doesn't seem fair.  When the ghosts touch Pacman he needs to DIE!  We also need to start him off with 3 or 4 lives, and when all lives are gone, the game is over.  Then we would have something that we could actually call a game.  So, in the next section we'll make it so the ghosts can actually kill Pacman.
level14.zip
File Size: 40 kb
File Type: zip
Download File