def __init__(self, *args, **kwargs): ''' @ivar _collision_grid: Objects that collide with others @ivar _game_running: True if we haven't gotten a Game Over @ivar group_list: list of pygame.Groups, rendered in ascending order @ivar hud_text: dict of HUD items that give info to the player @ivar key_actions: dict of functions to call when a given key is pressed @ivar _mouse_actions: dict of Blocks to drop on mouse click, only if config.DEBUG @ivar _ship: The player character @ivar _time: Time limit for the game in seconds (no limit if 0) @ivar _ufo: The UFO_GROUP object that, when shot, can destroy many blocks ''' from game.mainmenu import MainMenu ### Local Variables #################################################### global GAME_TEXT GAME_TEXT = config.load_text('ingame', settings.get_language_code()) rect = config.SCREEN_RECT ######################################################################## ### Object Attributes ################################################## self._game_running = True self.group_list = [bg.STARS_GROUP, BG, BLOCKS, UFO_GROUP, ENEMIES, ENEMY_BULLETS, PLAYER, PARTICLES, HUD] self._collision_grid = CollisionGrid(4, 4, 1, self.group_list) self.hud_text = HUD_TEXT( make_text('' , SCORE_LOCATION), make_text('' , LIVES_LOCATION), make_text('' , TIME_LOCATION ).center(), make_text(GAME_TEXT[2], GAME_OVER_LOC ).center(), make_text(GAME_TEXT[3], FIRE_LOCATION ).center(), make_text(GAME_TEXT[4], WAVE_LOCATION ).center(), make_text(GAME_TEXT[5], GAME_OVER_LOC ).center(), ) self._ship = Ship() self.key_actions = { K_ESCAPE: partial(self.change_state, MainMenu) , K_F1 : config.toggle_fullscreen , K_SPACE : self._ship.on_fire_bullet , K_c : null_if_debug(blockgrid.clean_up) , K_e : null_if_debug(partial(self._ship.instadie, None)) , K_f : null_if_debug(config.toggle_frame_limit) , K_i : null_if_debug(self.__ship_life) , K_k : partial(self._ship.change_state, Ship.STATES.DYING), K_p : self._pause_game , K_u : null_if_debug(self.__add_ufo) , K_PRINT : config.take_screenshot, K_F12 : config.take_screenshot, K_SYSREQ: config.take_screenshot, } self._mode = kwargs['time'] if 'time' in kwargs else -1 self._time = self._mode * 60 + 60 #In frames self._ufo = UFO() ######################################################################## ### Preparation ######################################################## PLAYER.add(self._ship, self._ship.flames, self._ship.my_bullet, self._ship.light_column) UFO_GROUP.add(self._ufo) HUD.add(self.hud_text.score, self.hud_text.wave) if self._mode > -1: #If this is a time attack mode... HUD.add(self.hud_text.time) gamedata.lives = 1 else: HUD.add(self.hud_text.lives) global DEBUG_KEYS if not config.DEBUG and DEBUG_KEYS: #If this is a release build... for i in DEBUG_KEYS: #For every debug action... del self.key_actions[i] DEBUG_KEYS = None BG.add(bg.EARTH, bg.GRID) enemysquadron.reset() enemysquadron.start() config.play_music(MUSIC_PATHS[self._mode])
class InGameState(GameState): def __init__(self, *args, **kwargs): ''' @ivar _collision_grid: Objects that collide with others @ivar _game_running: True if we haven't gotten a Game Over @ivar group_list: list of pygame.Groups, rendered in ascending order @ivar hud_text: dict of HUD items that give info to the player @ivar key_actions: dict of functions to call when a given key is pressed @ivar _mouse_actions: dict of Blocks to drop on mouse click, only if config.DEBUG @ivar _ship: The player character @ivar _time: Time limit for the game in seconds (no limit if 0) @ivar _ufo: The UFO_GROUP object that, when shot, can destroy many blocks ''' from game.mainmenu import MainMenu ### Local Variables #################################################### global GAME_TEXT GAME_TEXT = config.load_text('ingame', settings.get_language_code()) rect = config.SCREEN_RECT ######################################################################## ### Object Attributes ################################################## self._game_running = True self.group_list = [bg.STARS_GROUP, BG, BLOCKS, UFO_GROUP, ENEMIES, ENEMY_BULLETS, PLAYER, PARTICLES, HUD] self._collision_grid = CollisionGrid(4, 4, 1, self.group_list) self.hud_text = HUD_TEXT( make_text('' , SCORE_LOCATION), make_text('' , LIVES_LOCATION), make_text('' , TIME_LOCATION ).center(), make_text(GAME_TEXT[2], GAME_OVER_LOC ).center(), make_text(GAME_TEXT[3], FIRE_LOCATION ).center(), make_text(GAME_TEXT[4], WAVE_LOCATION ).center(), make_text(GAME_TEXT[5], GAME_OVER_LOC ).center(), ) self._ship = Ship() self.key_actions = { K_ESCAPE: partial(self.change_state, MainMenu) , K_F1 : config.toggle_fullscreen , K_SPACE : self._ship.on_fire_bullet , K_c : null_if_debug(blockgrid.clean_up) , K_e : null_if_debug(partial(self._ship.instadie, None)) , K_f : null_if_debug(config.toggle_frame_limit) , K_i : null_if_debug(self.__ship_life) , K_k : partial(self._ship.change_state, Ship.STATES.DYING), K_p : self._pause_game , K_u : null_if_debug(self.__add_ufo) , K_PRINT : config.take_screenshot, K_F12 : config.take_screenshot, K_SYSREQ: config.take_screenshot, } self._mode = kwargs['time'] if 'time' in kwargs else -1 self._time = self._mode * 60 + 60 #In frames self._ufo = UFO() ######################################################################## ### Preparation ######################################################## PLAYER.add(self._ship, self._ship.flames, self._ship.my_bullet, self._ship.light_column) UFO_GROUP.add(self._ufo) HUD.add(self.hud_text.score, self.hud_text.wave) if self._mode > -1: #If this is a time attack mode... HUD.add(self.hud_text.time) gamedata.lives = 1 else: HUD.add(self.hud_text.lives) global DEBUG_KEYS if not config.DEBUG and DEBUG_KEYS: #If this is a release build... for i in DEBUG_KEYS: #For every debug action... del self.key_actions[i] DEBUG_KEYS = None BG.add(bg.EARTH, bg.GRID) enemysquadron.reset() enemysquadron.start() config.play_music(MUSIC_PATHS[self._mode]) ######################################################################## def __del__(self): super().__del__() BLOCKS.empty() pygame.mixer.stop() for i in MODULE_CLEANUP: i.clean_up() def events(self, events): key_actions = self.key_actions for e in events: #For all events passed in... if e.type == KEYDOWN and e.key in key_actions: #If a key is pressed... if self._game_running or (not self._game_running and e.key == K_SPACE): #If we haven't gotten a game over... key_actions[e.key]() elif config.DEBUG and e.type == MOUSEBUTTONDOWN: #If a mouse button is clicked and we're in debug mode... if e.button < 4: self.__make_block(e.pos[0], MOUSE_ACTIONS[e.button]) else: self.__make_block(e.pos[0], None, True) def logic(self): enemysquadron.update() blockgrid.update() self._collision_grid.update() GameState.logic(self) if self._time > -1 and self._game_running: #If this is a timed game... self._time -= 1 if not self._time: #If we run out of time... gamedata.lives = 0 enemysquadron.increase_difficulty() if self._game_running: gamedata.alarm = blockgrid.is_above_threshold() config.loop_sound(ALARM if gamedata.alarm else None) else: config.loop_sound(None) if self._game_running and (not gamedata.lives or Block.block_full): #If we run out of lives or the blocks go past the top of the screen... pygame.mixer.music.fadeout(FADE_TIME) self._ship.change_state(Ship.STATES.DYING) self._ufo.change_state(UFO.STATES.GAMEOVER) self._ufo.kill() enemysquadron.celebrate() self._game_running = False gamedata.alarm = False elif not self._game_running: #If we've gotten a Game Over... if not self._ship.respawn_time: #Once the ship's been destroyed... for i in (self._ship, self._ship.flames, self._ship.light_column): i.kill() if not pygame.mixer.music.get_busy(): #If the song has faded out... HUD.add(self.hud_text.game_over, self.hud_text.press_fire) config.play_music(GAME_OVER_PATH) self.__game_over() def render(self): hud = partial(make_text, surfaces=True) if blockgrid.any_active(): self.group_list[2] = BLOCKS else: blockgrid.cache_block_image() self.group_list[2] = blockgrid.block_buffer if gamedata.score != gamedata.prev_score: #If our score has changed since the last frame... self.hud_text.score.image = hud("%s: %i" % (GAME_TEXT[0], gamedata.score)) gamedata.prev_score = gamedata.score if gamedata.lives != gamedata.prev_lives and self.hud_text.lives.alive(): #If we've gained or lost lives since the last frame... self.hud_text.lives.image = hud("%s: %i" % (GAME_TEXT[1], gamedata.lives)) gamedata.prev_lives = gamedata.lives if gamedata.wave != gamedata.prev_wave: self.hud_text.wave.image = hud("%s %i" % (GAME_TEXT[4], gamedata.wave)) gamedata.prev_wave = gamedata.wave if self._time >= 0: #If we haven't run out of time, and we're actually in timed mode... time_left = ((self._time // 60 // 60), (self._time // 60) % 60) self.hud_text.time.image = hud(TIME_FORMAT.format(*time_left)) GameState.render(self) if not self._ship.image.get_alpha(): #If our ship is invisible... pygame.draw.circle(config.screen, color.WHITE, self._ship.rect.center, int(150*log1p((3 * 60) - self._ship.respawn_time)) + 32, 16) pygame.display.flip() def __make_block(self, position, color=choice(color.LIST), special=False): ''' @param position: Position to release the Block (it'll snap to the grid) @param color: Color of the Block that will be released ''' if not special: #If we're not adding a special block... BLOCKS.add(block.get_block([position, 0.0], color)) else: UFO.BLOCK_GROUP.add(block.get_block([position, 0.0], special=True)) def __add_ufo(self): if self._ufo.state == UFO.STATES.IDLE: #If the UFO_GROUP is not currently on-screen... UFO_GROUP.add(self._ufo) self._ufo.change_state(UFO.STATES.APPEARING) def __ship_life(self): gamedata.lives += 30 def __game_over(self): from game.mainmenu import MainMenu kwargs={ 'next' : MainMenu , 'score': gamedata.score, 'mode' : self._mode , } self.key_actions[K_SPACE] = partial(self.change_state, HighScoreState, **kwargs) def _pause_game(self): HUD.add(self.hud_text.pause) for i in chain(BLOCKS, ENEMIES): i.image = i.current_frame_list[id(color.WHITE)][i._anim] self.render() config.toggle_pause() HUD.remove(self.hud_text.pause) for i in chain(BLOCKS, ENEMIES): i.image = i.current_frame_list[id(i.color)][i._anim]