'''lecture_33_pacman.py Simple implementation of the game Pac-Man Oliver W. Layton CS 151: Computational Thinking: Visual Media Fall 2020 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, moveDist=30, numPellets=20, collisionRadius=30): self.moveDist = moveDist self.collisionRadius = collisionRadius self.screen = turtle.Screen() self.screen.setup(width=800, height=800) self.screen.bgcolor('black') self.screen.title('Pacman') self.pacman = turtle.Turtle() self.pacman.penup() # Change the turtle shape to look like a pacman self.screen.register_shape('pacman.gif') self.pacman.shape('pacman.gif') # Make pellets self.screen.tracer(False) self.pellets = self.makePellets(numPellets) self.screen.tracer(True) # setup all events self.setupEvents() def setupEvents(self): self.screen.onkeypress(self.goUp, "Up") self.screen.onkeypress(self.goDown, "Down") self.screen.onkeypress(self.goLeft, "Left") self.screen.onkeypress(self.goRight, "Right") # Change the screen color randomly whenever the user clicks the game window self.screen.onclick(self.changeScreenColor, 1) # 1 means "left click" # Call self.checkCollisions ONCE 50 msec from now self.screen.ontimer(self.checkCollisions, 150) def goUp(self): self.pacman.setheading(90) self.pacman.forward(self.moveDist) def goDown(self): self.pacman.setheading(270) self.pacman.forward(self.moveDist) def goLeft(self): self.pacman.setheading(180) self.pacman.forward(self.moveDist) def goRight(self): self.pacman.setheading(0) self.pacman.forward(self.moveDist) def makePellets(self, numPellets): pellets = [] for i in range(numPellets): pellet = turtle.Turtle() pellet.penup() pellet.color('white') pellet.shape('circle') randX = random.randint(-self.screen.window_width()/2, self.screen.window_width()/2) randY = random.randint(-self.screen.window_height()/2, self.screen.window_height()/2) pellet.goto(randX, randY) pellets.append(pellet) return pellets def checkCollisions(self): # print('In check collisions!', random.random()) # Check if the pacman is close to any pellet right now pacmanX = self.pacman.xcor() pacmanY = self.pacman.ycor() # Check if close to ANY pellet for pellet in self.pellets: pellX = pellet.xcor() pellY = pellet.ycor() # Compare pacman and pellet x and y values if abs(pacmanX - pellX) < self.collisionRadius and abs(pacmanY - pellY) < self.collisionRadius: # If both pacman x and y are close enough to pellet, they are close pellet.hideturtle() # When done checking for collisions, add another event to call this function again in 50 msec self.screen.ontimer(self.checkCollisions, 150) def changeScreenColor(self, x, y): '''Parameters x and y needed when doing a callback from onclick because turtle is passing in automatically the (x, y) coordinate where the mouse is where the user clicked. ''' print('User clicked (x, y) = ', x, y) self.screen.bgcolor(random.random(), random.random(), random.random()) def run(self): # Now accept keyboard presses and have them do things based on keyboard callback events # that we have set up until now self.screen.listen() # Keep the window open (last line of our game code), accept events to come in (keyboard and # others). Think of as generalization of exitonclick. self.screen.mainloop() if __name__ == '__main__': game = PacMan() game.run()