class Game: def __init__(self): # pygame initializations pygame.init() self.screen = pygame.display.set_mode(s.SCREEN_SIZE) pygame.display.set_caption('Blasteroids') self.clock = pygame.time.Clock() self.volume = .1 Sounds.set_se_volume(self.volume) self.wave_font = pygame.font.SysFont('arialblack', 35) self.score_font = pygame.font.SysFont('arialblack', 17) # background and cursor surfaces self.surfaces = {'background': pygame.image.load('assets/background.png').convert(), 'cursor': pygame.image.load('assets/cursor.png').convert_alpha(), 'tower': pygame.image.load('assets/tower.png').convert_alpha(), 'hp_outline': pygame.image.load('assets/health_bar_outline.png').convert_alpha()} # game's main variables self.health = 100 self.inv = Inventory() self.current_weapon = self.inv.armory['cannon'] self.wave = Wave() self.score = 0 self.firing = False self.auto_fire = False def play(self): # Show title splash screen, start main game loop once title is closed title_splash = TitleScreen(self.screen) title_splash.play_screen() Sounds.play_music(Sounds.MAIN_MUSIC) # main loop while 1: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() # Shoot stuff (toggle auto-fire): elif event.type == pygame.MOUSEBUTTONDOWN: self.firing = True elif event.type == pygame.MOUSEBUTTONUP: self.firing = False # Keyboard press events: elif event.type is pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: pygame.quit() quit() # Toggle full screen with 'f' key: elif event.key == pygame.K_f: self._toggle_full_screen() # Toggle sound effects with ''n' key: elif event.key == pygame.K_n: if Sounds.get_se_volume() == 0: Sounds.set_se_volume(self.volume) else: Sounds.set_se_volume(0) # Toggle music with 'm' key: elif event.key == pygame.K_m: if Sounds.get_music_volume() == 0: Sounds.set_music_volume(self.volume) else: Sounds.set_music_volume(0) # Toggle auto fire with 'r' key: elif event.key == pygame.K_r: if not self.auto_fire: self.auto_fire = True else: self.auto_fire = False # Switch weapons with '1' or '2' keys: elif event.key == pygame.K_1: self.switch_weapons('cannon') elif event.key == pygame.K_2: self.switch_weapons('laser gun') # check for game over instance if self.health <= 0: Sounds.stop_music() pygame.mouse.set_visible(True) go = GameOverScreen(self.screen) go.play_screen() self._reset() # enable rapid fire when holding down the mouse: if self.firing or self.auto_fire: self.current_weapon.fire(pygame.mouse.get_pos()) # blit most background images and update their positions self.display_and_update() # collision handlers self.collision_handler() self.remove_excess_sprites() self.check_damage_dealt() self.blit_health() # wave mechanics if self.wave.is_wave_intermission(): # if new wave just started (5 seconds ago or less), just show wave text: self.blit_wave_text() elif not self.wave.wave_is_over(): # wave ongoing, add asteroids: self.wave.add_asteroids() else: # wave ended, start new wave self.wave.start_new_wave() pygame.display.update() self.clock.tick(s.FPS) def switch_weapons(self, new_weapon): if self.current_weapon != self.inv.armory[new_weapon]: self.inv.armory[new_weapon].projectile_group.add( self.current_weapon.projectile_group ) self.current_weapon.projectile_group.empty() self.current_weapon = self.inv.armory[new_weapon] # blit backgrounds, projectiles, asteroids, score # update asteroid and projectile positions def display_and_update(self): self.screen.blit(self.surfaces['background'], (0, 0)) self.blit_projectiles() self.screen.blit(self.surfaces['tower'], s.TOWER_POS) self.blit_asteroids() score_text = self.score_font.render(str(self.score), 1, s.WHITE) self.screen.blit(score_text, s.SCORE_TEXT_POS) # display cross hair as mouse cursor x, y = pygame.mouse.get_pos() self.screen.blit(self.surfaces['cursor'], (x - 9, y - 9)) def collision_handler(self): for shot in self.current_weapon.projectile_group: for asteroid in self.wave.asteroid_group: # upon collision, destroy projectile and subtract asteroid health if pygame.sprite.collide_mask(shot, asteroid): self.current_weapon.projectile_group.remove(shot) asteroid.health -= self.current_weapon.damage if asteroid.health <= 0: # destroy asteroid if asteroid.type == 'large': self.wave.asteroid_group.add(asteroid.spawn_children()) self.score += asteroid.score self.wave.asteroid_group.remove(asteroid) Sounds.EXPLOSION.play() return def remove_excess_sprites(self): # remove projectiles falling outside of screen for p in self.current_weapon.projectile_group: if (p.position[0] < 0 or p.position[0] > s.SCREEN_WIDTH or p.position[1] < 0 or p.position[1] > s.SCREEN_HEIGHT): self.current_weapon.projectile_group.remove(p) def check_damage_dealt(self): # if an asteroid reaches its destination, deal damage to player and remove for a in self.wave.asteroid_group: if a.position[1] >= a.destination[1]: self.health -= a.damage self.wave.asteroid_group.remove(a) Sounds.HEALTH_LOSS.play() def blit_projectiles(self): self.current_weapon.projectile_group.update() self.current_weapon.projectile_group.draw(self.screen) def blit_asteroids(self): self.wave.asteroid_group.update() self.wave.asteroid_group.draw(self.screen) def blit_wave_text(self): wave_text = self.wave_font.render('W A V E ' + str(self.wave.wave_number + 1), 1, s.YELLOW) self.screen.blit(wave_text, s.WAVE_TEXT_POS) def blit_health(self): self.screen.blit(self.surfaces['hp_outline'], s.HEALTH_BAR_OUTLINE) remaining_health = self.health / 100.0 if self.health > 0: pygame.draw.rect(self.screen, s.RED, (s.HP_BAR_X, s.HP_BAR_Y, s.HP_BAR_LENGTH * remaining_health, s.HP_BAR_HEIGHT)) def _toggle_full_screen(self): if pygame.display.get_driver() == 'x11': pygame.display.toggle_fullscreen() else: if s.FULL_SCREEN: self.screen = pygame.display.set_mode(s.SCREEN_SIZE) else: self.screen = pygame.display.set_mode(s.SCREEN_SIZE, pygame.FULLSCREEN) s.FULL_SCREEN = not s.FULL_SCREEN self.screen.blit(self.screen.copy(), (0, 0)) pygame.display.update() def _reset(self): self.health = 100 self.inv = Inventory() self.current_weapon = self.inv.armory['cannon'] self.wave = Wave() self.score = 0