def run_game(self): game_over = True running = True while running: if game_over: self.show_go_screen() game_over = False self.all_sprites = pygame.sprite.Group() self.mobs = pygame.sprite.Group() self.enemies = pygame.sprite.Group() self.bullets = pygame.sprite.Group() self.powerups = pygame.sprite.Group() self.player = Player(self.settings, self.graphics_provider, self.sound_provider, self.bullets, self.all_sprites) self.all_sprites.add(self.player) for i in range(8): self.new_mob() for i in range(3): self.new_enemy() score = 0 # keep loop running at the right speed self.clock.tick(self.settings.FPS) # Process input (events) for event in pygame.event.get(): # check for closing window if event.type == pygame.QUIT: running = False # Update self.all_sprites.update() # check to see if a bullet hit a mob hits = pygame.sprite.groupcollide(self.mobs, self.bullets, True, True) for hit in hits: score += 50 - hit.radius random.choice(self.sound_provider.expl_sounds).play() expl = Explosion(hit.rect.center, 'large', self.graphics_provider) self.all_sprites.add(expl) if random.random() > 0.9: powerup = Powerup(hit.rect.center, self.settings, self.graphics_provider) self.all_sprites.add(powerup) self.powerups.add(powerup) self.new_mob() # check to see if a bullet hit an enemy hits = pygame.sprite.groupcollide(self.enemies, self.bullets, True, True) for hit in hits: score += 50 - hit.radius random.choice(self.sound_provider.expl_sounds).play() expl = Explosion(hit.rect.center, 'large', self.graphics_provider) self.all_sprites.add(expl) if random.random() > 0.9: powerup = Powerup(hit.rect.center, self.settings, self.graphics_provider) self.all_sprites.add(powerup) self.powerups.add(powerup) self.new_enemy() # check to see if a mob hit the player hits = pygame.sprite.spritecollide(self.player, self.mobs, True, pygame.sprite.collide_circle) for hit in hits: self.player.shield -= hit.radius * 2 expl = Explosion(hit.rect.center, 'small', self.graphics_provider) self.all_sprites.add(expl) self.new_mob() if self.player.shield <= 0: self.sound_provider.player_die_sound.play() death_explosion = Explosion(self.player.rect.center, 'player', self.graphics_provider) self.all_sprites.add(death_explosion) self.player.hide() self.player.lives -= 1 self.player.shield = 100 # check to see if player hit a powerup hits = pygame.sprite.spritecollide(self.player, self.powerups, True) for hit in hits: if hit.type == 'shield': self.player.shield += random.randrange(10, 30) self.sound_provider.shield_sound.play() if self.player.shield >= 100: self.player.shield = 100 if hit.type == 'gun': self.player.powerup() self.sound_provider.power_sound.play() # if the player died and the explosion has finished playing if self.player.lives == 0 and not death_explosion.alive(): game_over = True # Draw / render self.screen.fill(self.settings.colors.black) self.screen.blit(self.graphics_provider.background, self.graphics_provider.background_rect) self.all_sprites.draw(self.screen) self.draw_text(self.screen, str(score), 18, self.settings.WIDTH / 2, 10) self.draw_shield_bar(self.screen, 5, 5, self.player.shield) self.draw_lives(self.screen, self.settings.WIDTH - 100, 5, self.player.lives, self.graphics_provider.player_mini_img) # *after* drawing everything, flip the display pygame.display.flip()
class Game: # initialize pygame and create window def __init__(self): # sound buffer size decrease pygame.mixer.pre_init(44100, -16, 1, 512) pygame.init() pygame.mixer.init() pygame.display.set_caption("Space Shooter") self.screen = pygame.display.set_mode( (config.WIDTH, config.HEIGHT), pygame.HWSURFACE | pygame.DOUBLEBUF) self.clock = pygame.time.Clock() self.background = Background() self.init_explosion_images() self.score = 0 self.power_up_rate = 0.9 # default value: 0.9 # Float_Texts self.score_textes = [] self.shield_bonus_textes = [] # Sound init self.sound_handler = Sound_Handler() self.sound_laser = self.sound_handler.sounds["laser"][1] pygame.mixer.music.load(config.background_music) pygame.mixer.music.play(loops=-1) # Loop continuing conditions self.running = True self.gameover = True # Hiding cursor pygame.mouse.set_visible(False) def init(self): self.sprites = pygame.sprite.Group() self.mobs = pygame.sprite.Group() self.bullets = pygame.sprite.Group() self.power_ups = pygame.sprite.Group() for i in range(config.NB_MOBS): new_mob = Mob() new_mob.add(self.mobs, self.sprites) self.player = Player() self.sprites.add(self.player) self.score = 0 self.gameover = False def init_explosion_images(self): self.explosion_anim = {} self.explosion_anim['lg'] = [] self.explosion_anim['sm'] = [] self.explosion_anim['player'] = [] for i in range(9): img = pygame.image.load( config.regular_explosion_filenames[i]).convert_alpha() img_lg = pygame.transform.scale(img, (75, 75)) self.explosion_anim['lg'].append(img_lg) img_sm = pygame.transform.scale(img, (32, 32)) self.explosion_anim['sm'].append(img_sm) img_player = pygame.image.load( config.sonic_explosion_filenames[i]).convert_alpha() self.explosion_anim['player'].append(img_player) def draw_text(self, text, size, x, y, color): font = pygame.font.Font(config.font_name, size) text_surface = font.render(text, True, color) # antialiazed text_rect = text_surface.get_rect() text_rect.midtop = (x, y) self.screen.blit(text_surface, text_rect) def draw_shield_bar(self): x = 10 y = 10 BAR_LENGTH = 100 BAR_HEIGHT = 20 fill = (self.player.shield * 100) // self.player.initial_shield outline_rect = pygame.Rect(x, y, BAR_LENGTH, BAR_HEIGHT) fill_rect = pygame.Rect(x, y, fill, BAR_HEIGHT) pygame.draw.rect(self.screen, Color.GREEN.value, fill_rect) pygame.draw.rect(self.screen, Color.WHITE.value, outline_rect, 3) def draw_lives(self): for i in range(self.player.lives): img_rect = self.player.image_mini.get_rect() img_rect.x = config.WIDTH + (i - self.player.lives) * 40 img_rect.y = 5 self.screen.blit(self.player.image_mini, img_rect) def show_gameover_screen(self): waiting = True quitting = False while waiting: self.clock.tick(config.FPS) self.background.update() self.screen.blit(self.background.image, self.background.rect) self.screen.blit(self.background.image, (self.background.rect.x, self.background.rect.y - self.background.rect.h)) self.draw_text("Space Shooter", 44, config.WIDTH // 2, config.HEIGHT // 4 - 30, Color.WHITE.value) self.draw_text("--- Commands ---", 14, config.WIDTH // 2, (config.HEIGHT * 2) // 4 - 30, Color.WHITE.value) self.draw_text("[QD] or arrow keys to move", 14, config.WIDTH // 2, (config.HEIGHT * 2) // 4 + 30 - 30, Color.WHITE.value) self.draw_text("[Space] to fire", 14, config.WIDTH // 2, (config.HEIGHT * 2) // 4 + 50 - 30, Color.WHITE.value) self.draw_text("[Esc] to quit game", 14, config.WIDTH // 2, (config.HEIGHT * 2) // 4 + 70 - 30, Color.WHITE.value) self.draw_text("Press [Enter] to play", 22, config.WIDTH // 2, (config.HEIGHT * 3) // 4 + 70 - 30, Color.WHITE.value) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False quitting = True elif event.type == pygame.KEYDOWN: log.info("[waiting menu] [" + str(event) + "] pressed") if (event.key == pygame.K_ESCAPE): self.running = False quitting = True if event.key == pygame.K_RETURN: waiting = False self.sound_handler.play('bolt') if quitting: waiting = False log.info("Exiting the game over waiting loop loop") def process_inputs(self): keys = pygame.key.get_pressed() if keys[pygame.K_SPACE]: now = pygame.time.get_ticks() if now - self.player.last_shoot > self.player.shoot_delay and not self.player.hidden: self.player.last_shoot = now self.player.shoot(self.bullets) self.sprites.add(self.bullets) self.sound_handler.play("laser") for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False elif event.type == pygame.KEYDOWN: log.info("[" + str(event) + "] pressed") if (event.key == pygame.K_ESCAPE): self.gameover = True def update(self): self.background.update() self.sprites.update() # list of mobs collided with player ; mobs are deleted mob_hits_with_player = pygame.sprite.spritecollide( self.player, self.mobs, True, pygame.sprite.collide_circle) for mob_hit in mob_hits_with_player: self.sound_handler.play("player_hit") self.player.shield -= mob_hit.radius * 2 expl = Explosion(self.explosion_anim, mob_hit.rect.center, 'sm') self.sprites.add(expl) new_mob = Mob() new_mob.add(self.mobs, self.sprites) if self.player.shield < 0: self.sound_handler.play("player_death") self.death_explosion = Explosion(self.explosion_anim, self.player.rect.center, 'player') self.sprites.add(self.death_explosion) self.player.hide() self.player.lives -= 1 self.player.shield = self.player.initial_shield # check if player died if self.player.lives == 0 and not self.death_explosion.alive(): self.gameover = True log.info("Game Over!") log.info("Score: " + str(self.score)) # list of mobs collided with the bullets ; both are deleted mob_hits_with_bullets = pygame.sprite.groupcollide( self.mobs, self.bullets, True, True) for mob_hit in mob_hits_with_bullets: self.sound_handler.play("explosion") points_gained = 60 - mob_hit.radius self.score += points_gained log.info("Hit Radius: " + str(mob_hit.radius)) self.score_textes.append( Float_Text(str(points_gained), 60, mob_hit.rect.midtop[0], mob_hit.rect.midtop[1] - 10)) expl = Explosion(self.explosion_anim, mob_hit.rect.center, 'lg') self.sprites.add(expl) new_mob = Mob() # respawn a new mob new_mob.add(self.mobs, self.sprites) if random.random() > self.power_up_rate: # 90% power = Power_Up(mob_hit.rect.center) power.add(self.sprites, self.power_ups) # list of power_ups collided with player ; power_ups are deleted power_up_hits_with_player = pygame.sprite.spritecollide( self.player, self.power_ups, True) for pu_hit in power_up_hits_with_player: level = pu_hit.level if pu_hit.type == 'shield': self.sound_handler.play("shield") bonus = 1 if level == 'bronze' else 3 if level == 'silver' else 9 bonus *= self.player.initial_shield // random.randrange( 12, 30) # 20 / 40 / 60 % self.player.shield += bonus self.player.shield = self.player.initial_shield if self.player.shield > self.player.initial_shield else self.player.shield self.shield_bonus_textes.append( Float_Text(str(bonus), 60, pu_hit.rect.midtop[0], pu_hit.rect.midtop[1] - 10)) elif pu_hit.type == 'bolt': self.sound_handler.play("bolt") self.player.shoot_bonus_counter += 3 * ( 1 if level == 'bronze' else 2 if level == 'silver' else 4) # moving floating text about points got from destroying mobs self.score_textes = list( filter(lambda x: x.lifetime > 0, self.score_textes)) for s in self.score_textes: s.update(2, 2) # moving floating text about shield bonuses self.shield_bonus_textes = list( filter(lambda x: x.lifetime > 0, self.shield_bonus_textes)) for s in self.shield_bonus_textes: s.update(1, 1) def draw(self): self.screen.blit(self.background.image, self.background.rect) self.screen.blit(self.background.image, (self.background.rect.x, self.background.rect.y - self.background.rect.h)) self.sprites.draw(self.screen) for score in self.score_textes: self.draw_text(score.text, 20, score.x, score.y, Color.WHITE.value) for bonus_text in self.shield_bonus_textes: self.draw_text(bonus_text.text, 20, bonus_text.x, bonus_text.y, Color.YELLOW.value) if self.player.shoot_bonus_counter > 0: self.draw_text(str(self.player.shoot_bonus_counter), \ min(15 + 3*self.player.shoot_bonus_counter, config.WIDTH), \ config.WIDTH//2, 50, Color.GREEN.value) self.draw_text(str(self.score), 20, config.WIDTH // 2, 10, Color.WHITE.value) self.draw_shield_bar() self.draw_lives() def render(self): pygame.display.flip() def run(self): previous_tick = pygame.time.get_ticks() exec_time = 0 wait_time = 0 while self.running: while self.gameover: self.show_gameover_screen() self.init() self.gameover = False # execution time exec_time = pygame.time.get_ticks() - previous_tick # log.info("[exec_time] " + str(exec_time) + " ms") # wait until 1/FPS has passed (16.6666667 ms) self.clock.tick(config.FPS) # keep loop running at the right speed # measure time waited wait_time = pygame.time.get_ticks() - previous_tick - exec_time # log.info("[wait_time]" + str(wait_time) + " ms") # log.info("[wait_time + exec_time] " + str(wait_time + exec_time) + " ms") # should be 15 or 16 print_percent_bar( exec_time, 16, True, '[0]', '[16]ms [exec_time=' + str(exec_time) + '|wait_time=' + str(wait_time) + ']') # sample time right after the end of the waiting previous_tick = pygame.time.get_ticks() # log.info("[Start] " + str(previous_tick / 1000) + " s") self.process_inputs() self.update() self.draw() self.render() log.info("Exiting the Game.run() loop") pygame.quit()
class TimeCrystal(Planet): def __init__(self, scene, pos, size, resources): super().__init__(scene, pos, size, resources) self.freeze_timer = 30 #FREEZE_INTERVAL self.frozen_ships = [] self.frozen_replicas = [] self.exp = None self.countdown = text.Text("", "tiny", self.pos + V2(0,-4), PICO_YELLOW, border=PICO_BLACK) self.countdown.offset = (0.5, 0.5) self.scene.ui_group.add(self.countdown) def generate_stranded_ships(self): stranded_ships = ['fighter', 'colonist', 'fighter', 'colonist'] if random.random() > 0.5: stranded_ships.append('bomber') else: stranded_ships.append('interceptor') theta = random.random() * 6.2818 for ship in stranded_ships: p = self.pos + helper.from_angle(theta) * random.randint(18,32) s = SHIPS_BY_NAME[ship](self.scene, p, self.scene.player_civ) if ship == 'colonist': s.set_pop(random.randint(2,5)) self.scene.game_group.add(s) self.freeze(s) theta += random.random() + 0.1 def add_ship(self, type, notify=True): print(type) super().add_ship(type, notify) print(self.ships) def generate_base_art(self): w = h = self.radius * 2 self.art = pygame.image.load(resource_path("assets/timecrystal.png")) def _generate_base_frames(self): self._sheet = self.art self._frame_width = 29 self._width = self._frame_width self._height = 37 self.art_inactive = self._sheet.subsurface((0,0,self._frame_width, self._height)) self.art_hover = self._sheet.subsurface((self._frame_width,0,self._frame_width, self._height)) self._recalc_rect() def _generate_frames(self): return def special_update(self, dt): self.freeze_timer -= dt if self.freeze_timer < 0: radius = 60 self.freeze_timer += FREEZE_INTERVAL self.exp = Explosion(self.pos, [PICO_BLUE, PICO_PINK,PICO_BLUE, PICO_PINK,PICO_BLUE, PICO_PINK], 1.0, radius, line_width=3) self.scene.game_group.add(self.exp) self.countdown.set_text("%d" % math.ceil(self.freeze_timer)) if self.exp: for s in self.scene.get_civ_ships(self.scene.player_civ): if (s.pos - self.exp.pos).length_squared() < self.exp.size ** 2: self.freeze(s) if not self.exp.alive(): self.exp = None return super().special_update(dt) def freeze(self, s): self.frozen_ships.append(s) self.scene.game_group.remove(s) replica = self.make_frozen_sprite(s) self.frozen_replicas.append(replica) self.scene.game_group.add(replica) def make_frozen_sprite(self, ship): outline_mask = pygame.mask.from_surface(ship.image, 127) surf = outline_mask.to_surface(setcolor=(*PICO_WHITE,255), unsetcolor=(0,0,0,0)) color_mask = pygame.mask.from_threshold(ship.image, (*PICO_GREEN,255), (2,2,2,255)) surf2 = color_mask.to_surface(setcolor=(*PICO_BLUE,255), unsetcolor=(0,0,0,0)) surf.blit(surf2,(0,0)) s = SimpleSprite(ship.pos, surf) s.offset = (0.5,0.5) return s def on_die(self): super().on_die() self.kill() def kill(self): for ship in self.frozen_ships: self.unfreeze_ship(ship) for replica in self.frozen_replicas: replica.kill() self.countdown.kill() sound.play_explosion() base_angle = random.random() * 6.2818 for x in range(self.image.get_width()): for y in range(self.image.get_height()): color = tuple(self.image.get_at((x,y))) if color[3] >= 128 and color[0:3] != PICO_BLACK: _,a = (V2(x,y) - V2(self.width/2,self.height/2)).as_polar() a *= 3.14159 / 180 ad = abs(helper.get_angle_delta(a, base_angle)) if ad > 3.14159/2: a = base_angle + 3.14159 else: a = base_angle pvel = helper.from_angle(a) * 6 p = particle.Particle([ color[0:3], color[0:3], DARKEN_COLOR[color[0:3]] ], 1, self.pos + V2(x - self.width // 2,y - self.height // 2), 1.25 + random.random() ** 2, pvel ) self.scene.game_group.add(p) return super().kill() def unfreeze_ship(self, ship): self.scene.game_group.add(ship) ship.set_state("returning") def is_buildable(self): return False
hit.rect.center) explode.effects.play() all_sprites.add(explode) # stats.life_percentage = player.shield # score_board.prep_shield_bar() newMob() if player.shield <= 0: ship_explode = Explosion(ui_settings, ship_explode_sheet, 64, 64, hit.rect.center) player.effects.play() all_sprites.add(ship_explode) player.hide() stats.lives_left -= 1 player.shield = 100 # Check if the player live is 0 if stats.lives_left == 0 and not ship_explode.alive(): game_over = True # Draw / render screen.fill(ui_settings.BLACK) screen.blit(background, background_rect) debris.scroll() # screen.blit(debris, debris_rect) score_board.show_scoreboard() all_sprites.draw(screen) # after drawing everything, flip the display pygame.display.flip() pygame.quit()
stone.move(t, (screen.get_width(), screen.get_height()), decrement_stones) if alien.alive(): #alien이 아직 살아있는 동안에 stone과의 충돌 여부를 확인. collided = pygame.sprite.groupcollide(stone_group, alien_group, False, True) if collided: #충돌하면 explosion위치를 alien있던 곳으로 옮기고 효과음. explosion.rect.x = \ (alien.rect.x + alien.rect.width/2) - \ explosion.rect.width/2 explosion.rect.y = \ (alien.rect.y + alien.rect.height/2) - \ explosion.rect.height/2 crash_sound.play() elif not explosion.alive(): # 외계인도 죽고 폭발 애니메이션도 끝났을 때. game_state = GAME_CLEAR # 외계인이 살아 있는데 돌멩이 수가 0이면 게임 오버. if alien.alive() and stone_count == 0: game_state = GAME_OVER if game_state == GAME_PLAY: # 게임 객체 업데이트 catapult_group.update() stone_group.update() alien_group.update() # 3) 게임 상태 그리기 background_group.update() background_group.draw(screen)