class Cherry(Sprite): CHERRY_SIZE = 30 def __init__(self, screen): super(Cherry, self).__init__() self.screen = screen.get_rect() self.image = ImageRect(screen, "cherry", Cherry.CHERRY_SIZE, Cherry.CHERRY_SIZE) self.rect = self.image.rect # Starts the cherry at this location self.rect.x = 300 self.rect.y = 390 def blitme(self): self.image.blitme() def update(self, pm): self.collide(pm) def collide(self, pm): """Collision for the dead ghost""" if pygame.sprite.collide_rect(self, pm): self.rect.x = 800 self.rect.y = 800 pm.score += 200 eat = pygame.mixer.Sound('sounds/eatfruit.wav') eat.play()
class Pill(Sprite): def __init__(self, screen, rect): super(Pill, self).__init__() self.im = ImageRect(screen, "pill", 10, 10) self.screen = screen self.im.rect = rect self.rect = self.im.rect def update(self): self.im.blitme()
class Dot(Sprite): def __init__(self, screen, rect): super(Dot, self).__init__() self.im = ImageRect(screen, "dot", 10, 10) self.screen = screen self.im.rect = rect self.rect = self.im.rect def update(self): self.im.blitme()
class PacMan(Sprite): def __init__(self, screen, row, col, maze): super(PacMan, self).__init__() self.screen = screen self.s_rect = screen.get_rect() self.im = ImageRect(screen, "pac_man_1", 18, 18) self.im.rect.centerx = col * 10 + 5 self.im.rect.centery = row * 10 + 5 self.maze = maze self.rect = self.im.rect self.moving_up = False self.moving_down = False self.moving_right = False self.moving_left = False self.speed = 10 self.state = 1 self.death_state = 1 self.dir = "" self.speed_timer = pygame.time.get_ticks() self.row = row self.col = col self.walls = [ 'T', 'B', 'R', 'L', 'G', 'M', 'N', 'O', 'Y', 'Z', 'W', 'X', 'S' ] self.dead = False self.sound_timer = pygame.time.get_ticks() self.finished = False def update(self): temp = "" if not self.dead: if self.moving_up and pygame.time.get_ticks( ) - self.speed_timer >= 100: temp = self.maze.rows[self.row - 1] val = temp[self.col] if val not in self.walls: self.im.rect.y -= self.speed self.row -= 1 self.im.blitme() self.speed_timer = pygame.time.get_ticks() self.dir = 'up' temp = "pac_man_up_" + str(self.state) elif self.moving_down and pygame.time.get_ticks( ) - self.speed_timer >= 100: temp = self.maze.rows[self.row + 1] val = temp[self.col] if val not in self.walls: self.row += 1 self.im.rect.y += self.speed self.im.blitme() self.speed_timer = pygame.time.get_ticks() self.dir = 'down' temp = "pac_man_down_" + str(self.state) elif self.moving_right and pygame.time.get_ticks( ) - self.speed_timer >= 100: temp = self.maze.rows[self.row] if self.col < 27: val = temp[self.col + 1] else: val = temp[0] if val not in self.walls: self.im.rect.x += self.speed self.col += 1 self.im.blitme() self.speed_timer = pygame.time.get_ticks() self.dir = 'right' temp = "pac_man_right_" + str(self.state) elif self.moving_left and pygame.time.get_ticks( ) - self.speed_timer >= 100: temp = self.maze.rows[self.row] val = temp[self.col - 1] if val not in self.walls: self.im.rect.x -= self.speed self.col -= 1 self.im.blitme() self.speed_timer = pygame.time.get_ticks() self.dir = 'left' temp = "pac_man_left_" + str(self.state) else: return temp if self.rect.x < 0: self.rect.centerx = 275 self.col = 27 elif self.rect.x > self.s_rect.width: self.rect.centerx = 5 self.col = 0 if pygame.time.get_ticks() - self.sound_timer >= 500: sound = pygame.mixer.Sound("sounds/pacman_chomp.wav") sound.play() self.sound_timer = pygame.time.get_ticks() self.rect = self.im.rect self.im = ImageRect(self.screen, temp, 18, 18) self.im.rect = self.rect if self.state >= 3: self.state = 1 else: self.state += 1 else: if self.death_state == 1: deathsound = pygame.mixer.Sound("sounds/pacmandies.wav") deathsound.set_volume(1) deathsound.play() if pygame.time.get_ticks( ) - self.speed_timer >= 200 and self.death_state < 12: temp = "pac_man_death_" + str(self.death_state) self.death_state += 1 self.rect = self.im.rect self.im = ImageRect(self.screen, temp, 18, 18) self.im.rect = self.rect self.speed_timer = pygame.time.get_ticks() elif pygame.time.get_ticks( ) - self.speed_timer >= 200 and self.death_state >= 12: self.finished = True def create_portal(self, portal_num): current_row = self.maze.rows[self.row] if self.dir == 'right': for x in range(self.col, len(current_row)): if current_row[x] == 'R': current_row = current_row[:x] + str( portal_num) + current_row[x + 1:] break elif self.dir == 'left': current_row = current_row[::-1] for x in range(self.col, len(current_row)): if current_row[x] == 'L': current_row = current_row[:x] + str( portal_num) + current_row[x + 1:] current_row = current_row[::-1] break self.maze.rows[self.row] = current_row self.maze.update_walls() def blitme(self): self.im.blitme()
class Red(Sprite): RED_SIZE = 30 def __init__(self, screen, maze): super(Red, self).__init__() self.screen = screen.get_rect() self.image = ImageRect(screen, "g_red_left_1", Red.RED_SIZE, Red.RED_SIZE) self.rect = self.image.rect # Starts the Red ghost at this location self.rect.x = 300 self.rect.y = 230 self.maze = maze # Setting movement flags - Red ghost starts moving left on game start self.direction = "u" self.move = "u" # Speed self.speed = 5 self.tick_dead = 30 self.tick_alive = 10 self.tick_speed = self.tick_alive # Index for images self.index = 1 self.dead_index = 1 self.dead_timer = 1 # Get available directions self.avail = [] # Set state of pacman to start as alive self.alive = True self.eat = False # Ticks self.timer = pygame.time.get_ticks() def update(self, maze, screen, pm): """Update position based on movement flags""" if gf.stop_ball(self, maze) is False and pygame.time.get_ticks() - self.timer >= self.tick_speed: self.timer = pygame.time.get_ticks() if self.move == "l": self.image.rect.x -= self.speed if self.eat is False: file = "g_red_left_" + str(math.floor(self.index)) else: file = "g_eyes_left" elif self.move == "r": self.image.rect.x += self.speed if self.eat is False: file = "g_red_right_" + str(math.floor(self.index)) else: file = "g_eyes_right" elif self.move == "d": self.image.rect.y += self.speed if self.eat is False: file = "g_red_down_" + str(math.floor(self.index)) else: file = "g_eyes_down" elif self.move == "u": self.image.rect.y -= self.speed if self.eat is False: file = "g_red_up_" + str(math.floor(self.index)) else: file = "g_eyes_up" else: file = "g_red_left_1" self.image = ImageRect(screen, file, Red.RED_SIZE, Red.RED_SIZE) self.image.rect = self.rect if self.index > 2.5: self.index = 1 else: self.index += .1 """For the dead ghosts""" if self.alive is False and self.eat is False: file = "evil_" + str(math.floor(self.dead_index)) self.image = ImageRect(screen, file, Red.RED_SIZE, Red.RED_SIZE) self.image.rect = self.rect if self.dead_timer > 20: self.alive = True else: self.dead_timer += .05 if self.dead_timer < 15: if self.dead_index > 2.5: self.dead_index = 1 else: self.dead_index += .1 else: if self.dead_index > 3.5: self.dead_index = 2 else: self.dead_index += .1 """Change speed of dead ghosts""" if self.alive is True: self.tick_speed = self.tick_alive elif self.alive is False: self.tick_speed = self.tick_dead self.ai(maze) self.dead_collide(pm, maze) def ai(self, maze): """Make the ghost move by itself""" """Making the ghost move out of the jail""" if self.move == "u" and self.rect == (300, 230, 30, 30): self.move = "l" elif 295 < self.rect.x < 305 and 325 < self.rect.y < 335: self.move = "u" if gf.stop_ball(self, maze) is True and self.eat is False: self.check_directions(maze) if len(self.avail) == 0: self.move = "l" self.move = "r" self.move = "u" self.move = "d" print("ERROR: NO MOVES AVAILABLE") else: rand = random.choice(self.avail) self.move = rand # if gf.stop_ball(self, maze) is True and self.eat is True: if self.eat is True: self.check_directions(maze) if self.rect.x < 190 and self.rect.y is not 230: if "r" in self.avail: self.move = "r" elif gf.stop_ball(self, maze): rand = random.choice(self.avail) self.move = rand elif self.rect.x > 410 and self.rect.y is not 230: if "l" in self.avail: self.move = "l" elif gf.stop_ball(self, maze): rand = random.choice(self.avail) self.move = rand elif self.rect.y < 230 and self.rect.x is not 300: if "d" in self.avail: self.move = "d" elif gf.stop_ball(self, maze): rand = random.choice(self.avail) self.move = rand elif self.rect.y > 230 and self.rect.x is not 300: if "u" in self.avail: self.move = "u" elif gf.stop_ball(self, maze): rand = random.choice(self.avail) self.move = rand elif self.rect.y is 230 and 190 < self.rect.x < 410: if 295 < self.rect.x < 305: self.move = "d" elif self.rect.x < 300: self.move = "r" elif self.rect.x > 300: self.move = "l" else: rand = random.choice(self.avail) self.move = rand def check_directions(self, maze): # check which directions are available to move self.avail.clear() self.direction = "u" if gf.brick_collision(self, maze) is False: if self.move is not "d": self.avail.append("u") self.direction = "d" if gf.brick_collision(self, maze) is False: if self.move is not "u": self.avail.append("d") self.direction = "l" if gf.brick_collision(self, maze) is False: if self.move is not "r": self.avail.append("l") self.direction = "r" if gf.brick_collision(self, maze) is False: if self.move is not "l": self.avail.append("r") def blitme(self): self.image.blitme() def dead_collide(self, pm, maze): """Collision for the dead ghost""" if pygame.sprite.collide_rect(self, pm) and self.alive is False: if self.alive is False and self.eat is False: pm.score += 200 eat = pygame.mixer.Sound('sounds/eatghost.wav') eat.play() self.eat = True if self.eat is True: for lines in maze.lines: if lines.colliderect(self): self.eat = False self.alive = True
class Ghost(Sprite): def __init__(self, ghost_type, p_man, screen, maze, row, col, blinky=None): super(Ghost, self).__init__() self.type = ghost_type self.p_man = p_man self.maze = maze self.row = row self.col = col self.blinky_lvl = 0 self.blink_timer = 0 self.blinky = blinky self.explosions = Group() if self.type == 'b': self.filename = "g_red_" self.targetcol = self.p_man.col self.targetrow = self.p_man.row self.scattercol = 26 self.scatterrow = 0 self.nextrow = self.row self.nextcol = self.col - 1 self.awake = True elif self.type == 'p': self.filename = "g_pink_" self.targetcol = self.p_man.col + 4 self.targetrow = self.p_man.row self.scattercol = 0 self.scatterrow = 0 self.nextrow = self.row self.nextcol = self.col - 1 self.awake = False elif self.type == 'i': self.filename = 'g_teal_' self.targetcol = 26 self.targetrow = 30 self.scattercol = 26 self.scatterrow = 30 self.nextrow = self.row self.nextcol = self.col - 1 self.awake = False elif self.type == 'c': self.filename = 'g_orng_' self.targetcol = 0 self.targetrow = 30 self.scattercol = 0 self.scatterrow = 30 self.nextrow = self.row self.nextcol = self.col - 1 self.awake = False self.screen = screen self.target = None self.speed = 200 self.leave = 0 self.state = 1 self.dir = 'left' self.nextdir = 'left' self.im = ImageRect(self.screen, self.filename+self.dir+'_'+str(self.state), 18, 18) self.eaten = False self.im.rect.centerx = col * 10 + 5 self.im.rect.centery = row * 10 + 5 self.rect = self.im.rect self.walls = ['T', 'B', 'R', 'L', 'G', 'M', 'N', 'O', 'Y', 'Z', 'W', 'X', 'S'] self.timer = pygame.time.get_ticks() self.frightened = False self.fear_timer = 0 self.start_time = pygame.time.get_ticks() def start(self, start_time): self.start_time = start_time def animate(self): if self.state == 1: self.state = 2 elif self.state == 2: self.state = 1 if self.frightened and pygame.time.get_ticks() - self.fear_timer < 4000: self.im = ImageRect(self.screen, 'g_blue_' + str(self.state), 18, 18) elif self.frightened and pygame.time.get_ticks() - self.fear_timer >= 4000: if self.state == 1: self.im = ImageRect(self.screen, 'g_white_' + str(self.state), 18, 18) if self.state == 2: self.im = ImageRect(self.screen, 'g_blue_' + str(self.state), 18, 18) else: self.im = ImageRect(self.screen, self.filename + self.dir + '_' + str(self.state), 18, 18) if self.eaten: self.im = ImageRect(self.screen, 'g_eaten_' + self.dir, 18, 18) self.im.rect.centerx = self.col * 10 + 5 self.im.rect.centery = self.row * 10 + 5 self.rect = self.im.rect def update(self, move): for explosion in self.explosions: if (pygame.time.get_ticks() - explosion.time_start) >= 100: self.explosions.remove(explosion) if not self.awake: if self.type == 'p': if pygame.time.get_ticks() - self.start_time > 2500: self.leave_house() elif self.type == 'i': if len(self.maze.dots.sprites()) <= 202: self.leave_house() elif self.type == 'c': if len(self.maze.dots.sprites()) <= 154: self.leave_house() else: self.leave_house() if pygame.time.get_ticks() - self.timer >= self.speed: self.animate() self.timer = pygame.time.get_ticks() if self.eaten: self.speed = 100 if self.row == 16 and self.col == 14: self.awake = False if pygame.time.get_ticks() - self.timer >= self.speed and self.awake: if move: self.col = self.nextcol self.row = self.nextrow self.dir = self.nextdir next_space = {} if self.dir == 'up': next_space = {'row': self.row - 1, 'col': self.col} elif self.dir == 'left': if self.col == 0 and self.row == 16: next_space = {'row': self.row, 'col': 27} else: next_space = {'row': self.row, 'col': self.col - 1} elif self.dir == 'down': next_space = {'row': self.row + 1, 'col': self.col} elif self.dir == 'right': if self.col == 27 and self.row == 16: next_space = {'row': self.row, 'col': 0} else: next_space = {'row': self.row, 'col': self.col + 1} adj_spaces = [{'row': next_space['row'] - 1, 'col': next_space['col'], 'dir': 'up'}, {'row': next_space['row'], 'col': next_space['col'] - 1, 'dir': 'left'}, {'row': next_space['row'] + 1, 'col': next_space['col'], 'dir': 'down'}, {'row': next_space['row'], 'col': next_space['col'] + 1, 'dir': 'right'}] behind = '' options = [] if self.dir == 'left': behind = 'right' elif self.dir == 'right': behind = 'left' elif self.dir == 'up': behind = 'down' elif self.dir == 'down': behind = 'up' for space in adj_spaces: if space['dir'] == behind: continue temp = self.maze.rows[space['row']] val = temp[space['col']] if val not in self.walls: options.append(space) if self.eaten and val == 'S': options.append(space) if len(options) > 1: self.update_target() target = Vec2d(self.targetcol, self.targetrow) min_distance = 28*36 for o in options: opt_vec = Vec2d(o['col'], o['row']) o['dist'] = opt_vec.get_distance(Vec2d(target)) if o['dist'] < min_distance: self.nextdir = o['dir'] min_distance = o['dist'] self.nextrow = next_space['row'] self.nextcol = next_space['col'] self.animate() self.timer = pygame.time.get_ticks() self.im.blitme() def find_target(self): if self.eaten: self.targetrow = 16 self.targetcol = 14 elif self.type == 'b': self.targetrow = self.p_man.row self.targetcol = self.p_man.col if len(self.maze.dots.sprites()) < 131 >= 65 and self.blinky_lvl == 0: self.speed *= 0.95 self.blinky_lvl = 1 elif len(self.maze.dots.sprites()) < 65 and self.blinky_lvl == 1: self.speed *= 0.95 self.blinky_lvl = 2 elif self.type == 'p': if self.p_man.dir == 'up': self.targetrow = self.p_man.row - 4 self.targetcol = self.p_man.col elif self.p_man.dir == 'down': self.targetrow = self.p_man.row + 4 self.targetcol = self.p_man.col elif self.p_man.dir == 'left': self.targetcol = self.p_man.col - 4 self.targetrow = self.p_man.row elif self.p_man.dir == 'right': self.targetcol = self.p_man.col + 4 self.targetrow = self.p_man.row print(str(self.targetcol) + ' ' + str(self.targetrow)) elif self.type == 'i': p_vec = Vec2d(self.p_man.col, self.p_man.row) if self.p_man.dir == 'up': p_vec.x -= 2 elif self.p_man.dir == 'down': p_vec += 2 elif self.p_man.dir == 'right': p_vec.x += 2 elif self.p_man.dir == 'left': p_vec.x -= 2 b_vec = Vec2d(self.blinky.col, self.blinky.row) col_vec = p_vec - b_vec col_vec *= 2 r_vec = b_vec + col_vec self.targetcol = r_vec.x self.targetrow = r_vec.y elif self.type == 'c': p_vec = Vec2d(self.p_man.col, self.p_man.row) c_vec = Vec2d(self.col, self.row) dist = c_vec.get_distance(p_vec) if dist > 8: self.targetrow = self.p_man.row self.targetcol = self.p_man.col else: self.targetcol = 0 self.targetrow = 30 def update_target(self): if self.frightened: if pygame.time.get_ticks() - self.fear_timer <= 6000: if self.p_man.row > 18: self.targetrow = 0 else: self.targetrow = 33 if self.p_man.col > 14: self.targetcol = 0 else: self.targetcol = 27 else: self.frightened = False if not self.eaten: if pygame.time.get_ticks() - self.start_time < 7000: self.targetrow = self.scatterrow self.targetcol = self.scattercol elif pygame.time.get_ticks() <= 27000: self.find_target() elif pygame.time.get_ticks() - self.start_time <= 34000: self.targetrow = self.scatterrow self.targetcol = self.scattercol elif pygame.time.get_ticks() - self.start_time <= 54000: self.find_target() elif pygame.time.get_ticks() - self.start_time <= 59000: self.targetrow = self.scatterrow self.targetcol = self.scattercol elif pygame.time.get_ticks() - self.start_time <= 79000: self.find_target() elif pygame.time.get_ticks() - self.start_time <= 84000: self.targetrow = self.scatterrow self.targetcol = self.scattercol else: self.find_target() def leave_house(self): if self.eaten: self.speed = 200 if self.leave < 3: if pygame.time.get_ticks() - self.timer >= self.speed: self.row -= 1 self.leave += 1 self.timer = pygame.time.get_ticks() self.im = ImageRect(self.screen, self.filename + self.dir + '_' + str(self.state), 18, 18) self.im.rect.centerx = self.col * 10 + 5 self.im.rect.centery = self.row * 10 + 5 self.rect = self.im.rect else: self.awake = True self.eaten = False self.frightened = False self.nextrow = self.row self.nextcol = self.col - 1 self.leave = 0 elif self.type == 'p': if self.leave < 3: if pygame.time.get_ticks() - self.timer >= self.speed: self.row -= 1 self.leave += 1 self.timer = pygame.time.get_ticks() self.im = ImageRect(self.screen, self.filename + self.dir + '_' + str(self.state), 18, 18) self.im.rect.centerx = self.col * 10 + 5 self.im.rect.centery = self.row * 10 + 5 self.rect = self.im.rect else: self.awake = True self.nextrow = self.row self.nextcol = self.col - 1 self.leave = 0 elif self.type == 'i': if pygame.time.get_ticks() - self.timer >= self.speed: if self.leave < 2: self.col += 1 self.leave += 1 self.timer = pygame.time.get_ticks() self.im = ImageRect(self.screen, self.filename + self.dir + '_' + str(self.state), 18, 18) self.im.rect.centerx = self.col * 10 + 5 self.im.rect.centery = self.row * 10 + 5 self.rect = self.im.rect elif self.leave <= 4: self.row -= 1 self.leave += 1 self.timer = pygame.time.get_ticks() self.im = ImageRect(self.screen, self.filename + self.dir + '_' + str(self.state), 18, 18) self.im.rect.centerx = self.col * 10 + 5 self.im.rect.centery = self.row * 10 + 5 self.rect = self.im.rect else: self.awake = True self.nextrow = self.row self.nextcol = self.col - 1 self.leave = 0 elif self.type == 'c': if pygame.time.get_ticks() - self.timer >= self.speed: if self.leave < 2: self.col -= 1 self.leave += 1 self.timer = pygame.time.get_ticks() self.im = ImageRect(self.screen, self.filename + self.dir + '_' + str(self.state), 18, 18) self.im.rect.centerx = self.col * 10 + 5 self.im.rect.centery = self.row * 10 + 5 self.rect = self.im.rect elif self.leave <= 4: self.row -= 1 self.leave += 1 self.timer = pygame.time.get_ticks() self.im = ImageRect(self.screen, self.filename + self.dir + '_' + str(self.state), 18, 18) self.im.rect.centerx = self.col * 10 + 5 self.im.rect.centery = self.row * 10 + 5 self.rect = self.im.rect else: self.awake = True self.nextrow = self.row self.nextcol = self.col - 1 self.leave = 0 def blitme(self): self.im.blitme()
class PM(Sprite): PAC_SIZE = 30 def __init__(self, screen, maze): super(PM, self).__init__() self.screen = screen.get_rect() self.image = ImageRect(screen, "p_left_2", PM.PAC_SIZE, PM.PAC_SIZE) self.rect = self.image.rect self.rect.x = self.screen.centerx - 10 self.rect.y = self.screen.centery + 110 self.maze = maze # Setting movement flags - Pacman starts moving left as game starts self.direction = "l" self.move = "l" # Speed self.speed = 5 self.tick_speed = 10 self.timer = pygame.time.get_ticks() # Index for images self.index = 1 self.dead_index = 1 self.sound_index = 1 # Set movement flags as false self.direction_l = False self.direction_r = False self.direction_u = False self.direction_d = False # For the scores self.lives = 3 self.score = 0 def update(self, maze, screen): """Update position based on movement flags""" if gf.stop_ball(self, maze) is False and pygame.time.get_ticks( ) - self.timer >= self.tick_speed: self.timer = pygame.time.get_ticks() if self.move == "l": self.image.rect.x -= self.speed file = "p_left_" + str(math.floor(self.index)) elif self.move == "r": self.image.rect.x += self.speed file = "p_right_" + str(math.floor(self.index)) elif self.move == "d": self.image.rect.y += self.speed file = "p_down_" + str(math.floor(self.index)) elif self.move == "u": self.image.rect.y -= self.speed file = "p_up_" + str(math.floor(self.index)) else: file = "p_up_1" self.image = ImageRect(screen, file, PM.PAC_SIZE, PM.PAC_SIZE) self.image.rect = self.rect if self.index >= 4: self.index = 1 else: self.index += .3 """For testing""" # print(self.rect.y) def ghost_collision(self, red, blue, pink, orange, stats, screen): """Check if pacman collides with ghost, loses a life""" if pygame.sprite.collide_rect(self, red) and red.alive is True: stats.game_pause = True die = pygame.mixer.Sound('sounds/death.wav') die.play() elif pygame.sprite.collide_rect(self, blue) and blue.alive is True: stats.game_pause = True die = pygame.mixer.Sound('sounds/death.wav') die.play() elif pygame.sprite.collide_rect(self, pink) and pink.alive is True: stats.game_pause = True die = pygame.mixer.Sound('sounds/death.wav') die.play() elif pygame.sprite.collide_rect(self, orange) and orange.alive is True: stats.game_pause = True die = pygame.mixer.Sound('sounds/death.wav') die.play() if stats.game_pause and red.alive is True: file = "p_dead_" + str(math.floor(self.dead_index)) self.image = ImageRect(screen, file, PM.PAC_SIZE, PM.PAC_SIZE) self.image.rect = self.rect if self.dead_index >= 6: self.dead_index = 1 stats.game_pause = False # Decrease amount of lives left self.lives -= 1 # Start again gf.reset_locations(self, red, blue, pink, orange, stats) else: self.dead_index += .2 if self.lives == 0: stats.game_over = True def blitme(self): self.image.blitme()