Moving the yellow circle around the maze almost feels like we're playing a game right? But something is missing. Well, for starters there aren't any enemies. Without obstacles like enemies there's no challenge. There's also no way of getting points, but we'll get to that later. Everyone knows that in Pacman there are four Ghosts or Monsters depending on your generation. I guess technically they're Monsters, but they look like Ghosts and I always thought they were supposed to be Ghosts, so I'm calling them Ghosts instead of Monsters. The deal with them is that they're constantly trying to kill Pacman for whatever reason. You may have also noticed that they all seem to have their own personalities. They also have their own names: Blinky, Pinky, Inky, and Clyde. In Ms. Pacman they have different names I think, but we won't worry about that. This section is just about the Ghosts in general. We'll first get one of the Ghosts up and running around the maze with Pacman. Then in a later section we'll get all four of them up there. The Ghosts are actually the most complicated part of this game, so it's easier to just focus on one Ghost at a time. Once we have that Ghost complete we can easily create as many Ghosts as we want with some minor changes for each Ghost to give them a unique personality.
Before we get into writing any code for the Ghosts, lets try and understand how they move around the maze. Like Pacman, the ghosts move around the maze from node to node. So a lot of the code that we wrote for Pacman will also apply to the ghosts with some minor differences.
So it makes sense (at least to me) that since Pacman and the Ghosts move around the maze in similar ways we should create a generic class from which they both can inherit. The class should describe any object that can move around the maze in a basic sense. Then we can use the Pacman and Ghost classes to be more specific in how they move around the maze. This way we're not writing the same code in multiple classes. We may also want to have other objects that move around the maze. So in the new file let's create a class called Entity. Any object that inherits from this class will have the basic ability to move around the maze on its own.
Most of what you see in this class was in the Pacman class with a few exceptions. First off, I'm importing something called 'randint' from the 'random' package. I'll explain more about this in a bit. I also added a 'visible' variable so that we can make any Entity invisible, which we'll need to do later on. You'll notice the change in the render method where we only draw the Entity when it is visible.
The setSpeed method may look weird and you may be asking why are we setting the speed based on the TILEWIDTH? Well, if you have a set speed like 100, that works well for a map that has 16x16 tiles. If you make the maze bigger with 32x32 tiles, for example, then Pacman will actually appear to move slower. He's actually moving at the same speed, but he has more ground to cover on a larger maze. If you make the maze with 8x8 tiles, then he'll appear to move twice as fast. So we need to adjust his speed depending on the size of the maze so we can get a similar experience no matter how large the maze is.
Along with what we entered in for the Entity class, here are some new methods. First off is the update method. This is slightly different than Pacman's update method, but it's largely the same. The main difference is that in Pacman's update method, the user is choosing the direction Pacman needs to go in. For the ghosts and any other entity, that's not the case. For the Entity class what will happen is that when the entity gets to a node, then it will just choose a random direction to go next. That's the basic movement of a basic Entity. That could be fine for many entities, and if you want your entity to do something else, then just overwrite the update method with your own update.
These two methods don't exist in the Pacman class. The validDirections method (not to be confused with the validDirection method), gets a list of valid directions the entity can move in. It does that by checking the node it's on. We simply loop through all 4 directions and see if the node connects to another node in that direction. If it does, then we make sure it's not the node we're coming from. Notice that if after all that the list is empty then that means the only valid direction is the direction from which we came, so we add that as the only valid direction.
The second method just chooses one of the directions randomly using the randint method we imported.
I know this section is about the Ghosts, but since we want Pacman to inherit from Entity, we might as well do that now. By inheriting we're saying that Pacman is an Entity. Anything that Entity can do, Pacman can do too. But Pacman will do more than an Entity because an Entity by itself is pretty boring.
In order to inherit from Entity we need to import it first. Then when creating the class instead of saying object which is the generic class all classes inherit from, we'll say Entity. Then in the __init__ method we need to call Entity__init__ as well. This way, any variables or methods that are defined inside of Entity are useable by Pacman. What's nice about this is that since we can put all of the generic stuff inside of Entity we can focus on what's unique about Pacman. So we can actually go ahead and delete anything in Pacman that we moved over to Entity. That goes for all of the variables except for name and color. We can delete all of the methods from Pacman except for __init__, getValidKey, update, and eatPellets. You're probably wondering why we didn't delete the update method from Pacman. After all, Entity has an update method as well. That's fine, if we have a method in the Pacman class that has the same name in the Entity class, then the method in the Pacman class will override the one in the Entity class.
If you go ahead and run the game you shouldn't notice any difference. That's good, there shouldn't be any difference, if there is then we messed up somewhere.
Other than deleting the methods that we mentioned above, make the following changes to the pacman.py file.