class NextLevel: audio = 4 def __init__(self, screen, score_controller, transition_time=5000): self.screen = screen self.score_controller = score_controller self.sound = Sounds(['pacman-beginning.wav'], keys=['transition'], channel=NextLevel.audio, volume=0.6) self.font = pygame.font.Font('fonts/LuckiestGuy-Regular.ttf', 32) self.ready_msg = self.font.render('Get Ready!', True, Scoreboard.white) self.ready_msg_rect = self.ready_msg.get_rect() ready_pos = screen.get_width() // 2, int(screen.get_height() * 0.65) self.ready_msg_rect.centerx, self.ready_msg_rect.centery = ready_pos self.level_msg = None self.level_msg_rect = None self.transition_time = transition_time self.transition_begin = None self.transition_show = False def prep_level_msg(self): text = 'level ' + str(self.score_controller.level) self.level_msg = self.font.render(text, True, Scoreboard.white) self.level_msg_rect = self.level_msg.get_rect() level_pos = self.screen.get_width() // 2, self.screen.get_height() // 2 self.level_msg_rect.centerx, self.level_msg_rect.centery = level_pos def set_show_transition(self): self.prep_level_msg() self.transition_begin = pygame.time.get_ticks() self.transition_show = True self.sound.play('transition') def draw(self): if abs(self.transition_begin - pygame.time.get_ticks()) > self.transition_time: self.transition_show = False else: self.screen.fill((0, 0, 0)) self.screen.blit(self.level_msg, self.level_msg_rect) if abs(self.transition_begin - pygame.time.get_ticks()) >= self.transition_time // 2: self.screen.blit(self.ready_msg, self.ready_msg_rect)
class Pacman(Sprite): audio = 0 yellow = (255, 255, 0) def __init__(self, screen, maze): super().__init__() self.screen = screen self.maze = maze self.dead = False self.direction = None self.event_map = { pygame.KEYDOWN: self.move, pygame.KEYUP: self.reset_movement } self.input_map = { pygame.K_UP: self.move_up, pygame.K_LEFT: self.move_left, pygame.K_DOWN: self.move_down, pygame.K_RIGHT: self.move_right, pygame.K_q: self.blue_portal, pygame.K_w: self.orange_portal } self.sound_manager = Sounds(sound_files=[ 'pacman-pellet-eat.wav', 'pacman-fruit-eat.wav', 'pacman-killed.wav', 'pacman-portal.wav' ], keys=['eat', 'fruit', 'dead', 'portal'], channel=Pacman.audio) self.death_frames = ImageRect('pacman-death.png', sheet=True, pos_offsets=[(0, 0, 32, 32), (32, 0, 32, 32), (0, 32, 32, 32), (32, 32, 32, 32), (0, 64, 32, 32), (32, 64, 32, 32)], resize=(self.maze.block_size, self.maze.block_size), animation_delay=150, repeat=False) self.pacmanx = ImageRect('pacman-horiz.png', sheet=True, pos_offsets=[(0, 0, 32, 32), (32, 0, 32, 32), (0, 32, 32, 32), (32, 32, 32, 32), (0, 64, 32, 32)], resize=(self.maze.block_size, self.maze.block_size), reversible=True) self.pacmany = ImageRect('pacman-vert.png', sheet=True, pos_offsets=[(0, 0, 32, 32), (32, 0, 32, 32), (0, 32, 32, 32), (32, 32, 32, 32), (0, 64, 32, 32)], resize=(self.maze.block_size, self.maze.block_size), reversible=True) self.spawn_set = self.maze.player_spawn[1] self.flip_mo = {'use_horiz': True, 'h_flip': False, 'v_flip': False} self.movement = False self.image, self.rect = self.pacmanx.get_image() self.portals = PortalController(screen, self, maze) def blue_portal(self): self.portals.fire_blue() def orange_portal(self): self.portals.fire_orange() def respawn(self): self.dead = False self.image, _ = self.pacmanx.get_image() self.death_frames.image_index = 0 def eat(self): score = 0 fruit_count = 0 ppellet = None collision = pygame.sprite.spritecollideany(self, self.maze.pellets) if collision: collision.kill() score += 10 self.sound_manager.play('eat') collision = pygame.sprite.spritecollideany(self, self.maze.fruits) if collision: collision.kill() score += (100 + (fruit_count * 200)) fruit_count += 1 self.sound_manager.play('fruit') collision = pygame.sprite.spritecollideany(self, self.maze.power_pellets) if collision: collision.kill() score += 50 ppellet = True self.sound_manager.play('eat') return score, fruit_count, ppellet def reset(self): self.rect.centerx, self.rect.centery = self.spawn_set def change_direction(self, event): if event.key in (pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT): self.moving = False def get_nearest_col(self): return (self.rect.x - (self.screen.get_width() // 5)) // self.maze.block_size def get_nearest_row(self): return (self.rect.y - (self.screen.get_height() // 12)) // self.maze.block_size def set_death(self): self.sound_manager.play('dead') self.dead = True self.image, _ = self.death_frames.get_image() def reset_portals(self): self.portals.clear_portals() def move(self, event): if event.key in self.input_map: self.input_map[event.key]() def move_up(self): if self.direction != 'u': self.direction = 'u' if self.flip_mo['v_flip']: self.pacmany.flip(False, True) self.flip_mo['v_flip'] = False self.flip_mo['use_horiz'] = False self.moving = True def move_left(self): if self.direction != 'l': self.direction = 'l' if not self.flip_mo['h_flip']: self.pacmanx.flip() self.flip_mo['h_flip'] = True self.flip_mo['use_horiz'] = True self.moving = True def move_down(self): if self.direction != 'd': self.direction = 'd' if not self.flip_mo['v_flip']: self.pacmany.flip(x_bool=False, y_bool=True) self.flip_mo['v_flip'] = True self.flip_mo['use_horiz'] = False self.movement = True def move_right(self): if self.direction != 'r': self.direction = 'r' if self.flip_mo['h_flip']: self.pacmanx.flip() self.flip_mo['h_flip'] = False self.flip_mo['use_horiz'] = True self.movement = True def reset_movement(self, event): if event.key in (pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT): self.movement = False def blit(self): self.portals.blit() self.screen.blit(self.image, self.rect)
class PortalController: PORTAL_AUDIO_CHANNEL = 3 def __init__(self, screen, user, maze): self.screen = screen self.maze = maze self.user = user self.sounds = Sounds( sound_files=['portal-open.wav', 'portal-travel.wav'], keys=['open', 'travel'], channel=PortalController.PORTAL_AUDIO_CHANNEL) self.blue_portal = pygame.sprite.GroupSingle( ) # portals as GroupSingle, which only allows one per group self.blue_projectile = None self.orange_portal = pygame.sprite.GroupSingle() self.orange_projectile = None self.portal_directions = {'l': 'r', 'r': 'l', 'u': 'd', 'd': 'u'} def clear_portals(self): self.blue_portal.empty() self.orange_portal.empty() self.blue_projectile = None self.orange_projectile = None def fire_blue(self): if self.user.direction is not None: self.blue_projectile = PortalProjectile( screen=self.screen, source=self.user, direction=self.user.direction, p_type=Portal.P_TYPE_1) def fire_orange(self): if self.user.direction is not None: self.orange_projectile = PortalProjectile( screen=self.screen, source=self.user, direction=self.user.direction, p_type=Portal.P_TYPE_2) def create_blue(self, x, y, direction): if self.blue_portal: old_x, old_y = self.blue_portal.sprite.rect.x, self.blue_portal.sprite.rect.y self.maze.maze_blocks.add( Block(old_x, old_y, self.maze.block_size, self.maze.block_size, self.maze.block_image)) self.blue_portal.add( Portal(screen=self.screen, x=x, y=y, direction=direction, maze=self.maze, p_type=Portal.P_TYPE_1)) def create_orange(self, x, y, direction): if self.orange_portal: old_x, old_y = self.orange_portal.sprite.rect.x, self.orange_portal.sprite.rect.y self.maze.maze_blocks.add( Block(old_x, old_y, self.maze.block_size, self.maze.block_size, self.maze.block_image)) self.orange_portal.add( Portal(screen=self.screen, x=x, y=y, direction=direction, maze=self.maze, p_type=Portal.P_TYPE_2)) def update(self): self.blue_portal.update() self.orange_portal.update() if self.blue_projectile: self.blue_projectile.update() if pygame.sprite.spritecollideany(self.blue_projectile, self.blue_portal) or \ pygame.sprite.spritecollideany(self.blue_projectile, self.orange_portal): self.blue_projectile = None return collision = pygame.sprite.spritecollideany(self.blue_projectile, self.maze.maze_blocks) if collision: x, y = collision.rect.x, collision.rect.y collision.kill() direction = self.portal_directions[ self.blue_projectile.direction] self.blue_projectile = None self.create_blue(x, y, direction) self.sounds.play('open') elif self.blue_projectile.is_off_screen(): self.blue_projectile = None if self.orange_projectile: self.orange_projectile.update() if pygame.sprite.spritecollideany(self.orange_projectile, self.blue_portal) or \ pygame.sprite.spritecollideany(self.orange_projectile, self.orange_portal): self.orange_projectile = None return collision = pygame.sprite.spritecollideany(self.orange_projectile, self.maze.maze_blocks) if collision: x, y = collision.rect.x, collision.rect.y collision.kill() direction = self.portal_directions[ self.orange_projectile.direction] self.orange_projectile = None self.create_orange(x, y, direction) self.sounds.play('open') elif self.orange_projectile.is_off_screen(): self.orange_projectile = None def portables_usable(self): return self.blue_portal and self.orange_portal def collide_portals(self, other): return pygame.sprite.spritecollideany(other, self.blue_portal) or \ pygame.sprite.spritecollideany(other, self.orange_portal) def check_portals(self, *args): for arg in args: if pygame.sprite.spritecollideany( arg, self.blue_portal) and self.orange_portal: i, j = self.orange_portal.sprite.get_nearest_row( ), self.orange_portal.sprite.get_nearest_col() if self.orange_portal.sprite.direction == 'l': j -= 1 elif self.orange_portal.sprite.direction == 'r': j += 1 elif self.orange_portal.sprite.direction == 'u': i -= 1 else: i += 1 x, y = ((self.screen.get_width()) // 5 + (j * self.maze.block_size)), \ ((self.screen.get_height()) // 12 + (i * self.maze.block_size)) arg.rect.x, arg.rect.y = x, y self.sounds.play('travel') elif pygame.sprite.spritecollideany( arg, self.orange_portal) and self.blue_portal: i, j = self.blue_portal.sprite.get_nearest_row( ), self.blue_portal.sprite.get_nearest_col() if self.blue_portal.sprite.direction == 'l': j -= 1 elif self.blue_portal.sprite.direction == 'r': j += 1 elif self.blue_portal.sprite.direction == 'u': i -= 1 else: i += 1 x, y = ((self.screen.get_width() // 5) + (j * self.maze.block_size)), \ ((self.screen.get_height() // 12) + (i * self.maze.block_size)) arg.rect.x, arg.rect.y = x, y self.sounds.play('travel') def blit(self): if self.blue_projectile: self.blue_projectile.blit() if self.orange_projectile: self.orange_projectile.blit() if self.blue_portal: self.blue_portal.sprite.blit() if self.orange_portal: self.orange_portal.sprite.blit()
class Game: def __init__(self, modes): GPIO.setmode( GPIO.BCM) #set up to use gpio port numbers (instead of pin #s) self.buttons = Buttons() self.optos = Optos() self.lights = Lights() self.outlets = Outlets() self.sounds = Sounds() self.clock = Countdown(12) self.modes = modes self.last_time = time.localtime() def cleanup(self): self.lights.turn_off_all() GPIO.cleanup() #clean exit of GPIO ports def time(self): return int(round(time.time() * 1000)) def find_mode(self, name): return self.modes[name](self, name) def run(self, game_mode, state=None): start_state = game_mode.enter() state = state or start_state try: timer_start = self.time() while state: start_time = self.time() print("{}:{}".format(game_mode, state)) new_state = game_mode.enter_state(state) if isinstance(new_state, Exit): return new_state next_time = start_time + new_state.delay * 1000 next_state = None while not next_state: now = self.time() if now > next_time: next_state = new_state next_state.delay = 0 break state.timer = (now - timer_start) / 1000.0 ret = self.idle(game_mode) if isinstance(ret, Exit): return ret ret = game_mode.idle(state) if isinstance(ret, Exit): return ret if isinstance(ret, State): next_state = ret if next_state.state != state.state: game_mode.exit_state(state) timer_start = now state = next_state finally: game_mode.exit() def idle(self, game_mode): # This is global stuff if self.buttons.switched(Button.BACK): self.sounds.play("beep") if self.buttons.back: return Exit("racing") else: self.sounds.play("gurble") return Exit("quiet") if self.buttons.check((Button.GREEN, Button.RED, Button.YELLOW)): return Exit("songs") if game_mode.name == "songs": if self.buttons.black: self.sounds.volume_up() self.sounds.play("beep") if self.buttons.blue: self.sounds.volume_down() self.sounds.play("beep") # Put in stuff for time check & volume changes, e.g. # if it was before 7am and now it's after 7am # then return Exit("songs") if self.check_time(0): # At midnight self.sounds.set_volume(0.7) if self.check_time(2): # At 2am self.sounds.set_volume(0.2) if self.check_time(4): # At 4am return Exit("quiet") if self.check_time(8): # At 8am (choose wisely) self.sounds.set_volume(1) return Exit("songs") self.last_time = time.localtime() def play(self, name): game_mode = self.find_mode(name) state = None print("Starting {}".format(game_mode)) while True: result = self.run(game_mode, state) print("{} exited: {}".format(game_mode, result.value)) game_mode, state = self.mode_exited(game_mode, result.value) print("Switching to {}".format(game_mode)) def mode_exited(self, game_mode, value): return self.find_mode(value), None def check_time(self, hr): now = time.localtime() if hr == 0: return self.last_time.tm_hour > 20 return self.last_time.tm_hour < hr and now.tm_hour == hr