'''lecture_32_pacman.py Simple implementation of the game Pac-Man Oliver W. Layton CS 151: Computational Thinking: Visual Media Spring 2021 TODO: Create `PacMan` class - Constructor: Setup black screen, custom pac-man turtle shape UPDATE 1: Create `setupEvents` method with keypress events, and `play` to listen for events and start main game loop. UPDATE 2: Create `placePellets(nPellets)` which returns a list of pellets (Turtle objects that are the pellets). - Add timer event for checking collisions with pellets, have the method queue up another timer event so that it can repeat. UPDATE 3: Use "mouse" (or trackpad) clicks to perform an action (e.g. change background color) - Create changeColor(self, x, y) ''' import turtle import random class PacMan: def __init__(self, width=800, height=800, nPellets=50): self.screen = turtle.Screen() self.screen.setup(width=width, height=height) self.screen.bgcolor('black') self.screen.title('PacMan') # Makes my custom PacMan image accessible so that turtle can take on its shape self.screen.register_shape('pacman.gif') self.player = turtle.Turtle() # Set turtle shape to be the pacman image self.player.shape('pacman.gif') self.player.penup() # Amount pacman moves on each keypress self.distance = 20 # Make the pellets self.screen.tracer(False) # List of pellets is an instance variable self.pellets = self.makePellets(nPellets) self.screen.tracer(True) # Setup events self.setupEvents() # self.screen.exitonclick() def setupEvents(self): '''Define all the events and associated actions to take e.g. Keyboard presses ''' # We are NOT calling self.moveUp method NOW, so we do NOT use parenthesis # self.moveUp() <-- actually function now, NOT what we want. # NOTE: self. in front of moveUp bc this is a METHOD inside the class, NOT a function outside. # 2nd parameter is string representing the keyboard button name (you can look up all on # turtle website) self.screen.onkeypress(self.moveUp, 'Up') self.screen.onkeypress(self.moveDown, 'Down') self.screen.onkeypress(self.moveLeft, 'Left') self.screen.onkeypress(self.moveRight, 'Right') def moveUp(self): '''Moves pacman up by `self.distance` ''' self.player.setheading(90) self.player.forward(self.distance) def moveDown(self): '''Moves pacman down up by `self.distance` ''' self.player.setheading(270) self.player.forward(self.distance) def moveLeft(self): '''Moves pacman left by `self.distance` ''' self.player.setheading(180) self.player.forward(self.distance) def moveRight(self): '''Moves pacman right by `self.distance` ''' self.player.setheading(0) self.player.forward(self.distance) def makePellets(self, nPellets): '''Make a list of Turtle objects (that look like pellets). Place them in a random spot on the canvas. Return the list of pellets ('Turtles') ''' pellets = [] for i in range(nPellets): pellet = turtle.Turtle() pellet.shape('circle') pellet.color('white') pellet.penup() pellet.goto(600*random.random() - 300, 600*random.random() - 300) pellets.append(pellet) return pellets def checkCollisions(self): '''Checks for whether we have a collision between the player (Pacman) and one of the pellets. ''' for pellet in self.pellets: # 10 defines "how close is close" to detect that a collision occurs if abs(pellet.xcor() - self.player.xcor() < 10) and abs(pellet.ycor() - self.player.ycor() < 10): # We have a collision def play(self): # Actually accept events/wait for things to happen, and actually take action. # "Tell the screen to listen for events" self.screen.listen() # Generalization of exitonclick — hold the window open, allows game to run 'indefinitely' # until we intentionally close out (x out), allow to interact/play the game. # Think of as infinite while loop...this should be last step, we don't keep going beyond this # point self.screen.mainloop() # won't get here # print('hi') if __name__ == '__main__': # game = PacMan(nPellets=100) game = PacMan() game.play()