def update(self, d_time, players: pygame.sprite.Group, missile_wrapper: MissileWrapper): for e in self.sprites(): if e.life > 0: missile_wrapper.enemy_hit(e) for e in self.sprites(): if e.life > 0: missile_wrapper.enemy_aoe_hit(e) missile_wrapper.add_from_enemy(e.shoot()) if e.state is Enemy.State.DEAD: self.remove(e) if len(players.sprites()) > 1: for e in self.sprites(): dps = [Vector(p.rect.center[0] - e.rect.center[0], p.rect.center[1] - e.rect.center[1]).magnitude() for p in players.sprites()] min_dp = min(dps) for i in range(len(dps)): if min_dp == dps[i]: e.update(d_time, players.sprites()[i].rect.center) elif len(players.sprites()) == 1: super().update(d_time, players.sprites()[0].rect.center) if len(self.sprites()) < self.max_enemies: self.timer += d_time if self.timer > self.new_enemy_spawn_interval: self.add([self.enemy_prefab((random.randrange(0, self.screen.get_width(), 1), -30)) for i in range(self.new_enemies_number)]) self.timer = 0
def render(self, sprites: pygame.sprite.Group): self.display.fill((0, 0, 0)) for star in self.stars: pygame.draw.rect(self.display, (200, 200, 200), star) sprites.draw(self.display) pygame.display.update()
def update(self, frametime: int, food_group: pygame.sprite.Group): for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.KEYDOWN and event.key in self.shortcuts.keys( ): event: pygame.event.Event # Prevents movement to the opposite direction(snake would collide with itself) opposites = { Direction.N: Direction.S, Direction.S: Direction.N, Direction.W: Direction.E, Direction.E: Direction.W, } direction = self.shortcuts.get(event.key) if opposites.get(self.direction) != direction: self.new_direction = direction # Using frametime keeps the movement relatively stable despite the FPS the game is running at if self.frametime_counter >= self.frametime_for_step: self.direction = self.new_direction if self.new_head is None: self.step() else: head: SnakeUnit = self.sprites().pop() x_mov = self.direction.value[0] y_mov = self.direction.value[1] self.new_head.rect = head.rect.move(x_mov, y_mov) self.add(self.new_head) self.new_head = None self.frametime_counter = 0 head: SnakeUnit = self.sprites().pop() collided_foods = pygame.sprite.spritecollide(head, food_group, dokill=True) if collided_foods: self.new_head = SnakeUnit() food_group.add(Food(self)) # Kill snake if it is out of screen head: SnakeUnit = self.sprites().pop() if (head.rect.x < 0 or head.rect.x > Screen.WIDTH - head.rect.w or head.rect.y < 0 or head.rect.y > Screen.HEIGHT - head.rect.h): self.dead = True # Kill snake if it collides with itself if not self.dead: sprites: List[SnakeUnit] = self.sprites() head: SnakeUnit = sprites.pop() for sprite in sprites: if pygame.sprite.collide_rect(sprite, head): self.dead = True break else: self.frametime_counter += frametime
def check_play_button(ai_settings: Settings, stats: GameStats, screen: pygame.Surface, play_button: Button, sb: ScoreBoard, ship: Ship, aliens: pygame.sprite.Group, bullets: pygame.sprite.Group, mouse_x: int, mouse_y: int) -> NoReturn: """在晚间单机play按钮时开始新游戏""" button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y) if button_clicked and not stats.game_active: # 重置游戏设置 ai_settings.initialize_dynamic_settings() # 隐藏光标 pygame.mouse.set_visible(False) # 重置游戏统计信息 stats.reset_stats() stats.game_active = True # 重置记分牌图像 sb.prep_score() sb.prep_high_score() sb.prep_level() sb.prep_ships() # 清空外星人列表和子弹列表 aliens.empty() bullets.empty() # 创建一群新的外星人,并让飞船居中 create_fleet(ai_settings, screen, ship, aliens) ship.center_ship()
def update_fire(self, projectile_group: pygame.sprite.Group): if self.fire_timer > self.fire_delay: projectile_group.add( MultiProjectile(self.p_speed, self.rect.x + self.rect.w / 2, self.rect.bottom, [self.p_im], 0, self.p_count, self.p_fire_angle, self.p_spread).projectiles_group) self.fire_timer = 0 self.dirty = 1
def partie_perdue(hauteur_lave: int, générateur, liste_de_sprites: pygame.sprite.Group) -> None: """Vérifie si le joueur touche la lave, si oui, afficher qu'il a perdu puis le faire retourner au menu :param hauteur_lave: (int) la hauteur de la lave depuis le haut de la fenêtre de jeu :param générateur: le générateur de niveaux, l'accès est donné pour pouvoir afficher les platformes :param liste_de_sprites: une liste qui contient le joueur, permet d'afficher le joueur """ global niveau # Si le joueur touche la lave # Remet le niveau actif à 0 niveau = 0 # Dessiner tout le niveau et afficher qu'il a perdu générateur.draw() player.handle_keys() liste_de_sprites.update() liste_de_sprites.draw(screen) étiquette('Vous avez perdu!', 720, 400, 60) org_screen.blit(screen, (0, 0)) pygame.display.flip() sleep(1) # Faire attendre le joueur 3 secondes avant que le jeu ne le ramène au menu for i in range(3): screen.fill((0, 0, 0)) étiquette('Vous avez perdu!'.format(3 - i), 720, 400, 60) étiquette('Retour au menu dans {} secondes'.format(3 - i), 600, 500, 60) org_screen.blit(screen, (0, 0)) pygame.display.flip() sleep(1) # Retoune le joueur au menu principal menu_général()
def fire(self, projectiles_group: pygame.sprite.Group): # swap get_height and get_width because of rotation projectile = MultiProjectile(self.projectile_speed, self.x + self.rect.w / 2, self.y, self.attack_imgs, self.anim_delay, self.projectile_count, 90, self.projectile_spread) projectiles_group.add(projectile.projectiles_group)
def create_alien(ai_settings: Settings, screen: pygame.Surface, aliens: pygame.sprite.Group, alien_number: int, row_number: int) -> NoReturn: """创建一个外星人并将其放在当前行""" alien = Alien(ai_settings, screen) alien_width = alien.rect.width alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = int(alien.x) alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number aliens.add(alien)
def collision_pairs(grpSprites1: pygame.sprite.Group, grpSprites2: pygame.sprite.Group, fncCollided=pygame.sprite.collide_rect) -> List[Tuple[Sprite, Sprite]]: lstPairs = [] lstSpr1 = grpSprites1.sprites() lstSpr2 = grpSprites2.sprites() for i in range(len(lstSpr1)): for j in range(len(lstSpr2)): if fncCollided(lstSpr1[i], lstSpr2[j]): lstPairs.append((lstSpr1[i], lstSpr2[j])) return lstPairs
def draw(screen: pygame.Surface, background: pygame.Surface, framerate: int, all_sprites: pygame.sprite.Group, clock: pygame.time.Clock, grid: Grid, current_time: int, grid_visible: bool) -> None: screen.blit(background, [0, 0]) all_sprites.update() if grid_visible: grid.draw_grid(screen, current_time) all_sprites.draw(screen) pygame.display.flip() clock.tick(framerate)
def render_pipes(image_list: list, group: pygame.sprite.Group) -> Enemy: """Renders pipe images onto the screen. Pipe objects are created after a set number of milliseconds. The newly formed pipe is then added to the pipes group""" milliseconds = pygame.time.get_ticks() if milliseconds % 1500 < 15: characteristics = spawn_pipe(image_list) if characteristics is not None: pipe = Enemy(characteristics[0], characteristics[1], characteristics[2]) group.add(pipe) return pipe
def move_with_gravity(asteroids: pygame.sprite.Group): """ Function takes tuple of planets(asteroids) calculate their gravitational interaction. """ asteroids = tuple(asteroids) for asteroid in asteroids: asteroid.reset_forses() for asteroid_i in asteroids: for asteroid_j in asteroids: # In order for not to do the same action twice if asteroids.index(asteroid_i) < asteroids.index(asteroid_j): asteroid_i.gravitational_force(asteroid_j)
def _add_extra_numbers(self, pos_x: int, score: str, nums_images: Dict, nums_coords: List, nums_position: Tuple, score_sprites: pygame.sprite.Group) -> None: if len(score) > 1: for i in range(1, len(score)): if score[i] == score[0] or score[i] == score[i - 1]: extra_number = Image(self.nums_assets, nums_coords[i], nums_position) else: extra_number = nums_images[score[i]] pos_x += extra_number.rect.width + 2 extra_number.rect = (pos_x, nums_position[1]) score_sprites.add(extra_number)
def display_game(sprites: pygame.sprite.Group, live_blocks: Shape, solid_blocks: list): sprites.empty() for i in live_blocks: sprites.add(i) for i in solid_blocks: sprites.add(i) sprites.update() screen.blit(background, (0, 0)) sprites.draw(screen) pygame.display.flip()
def render_pipes(speed: int, timer: float, scaling: float, image_list: list, group: pygame.sprite.Group) -> Enemy: """Renders pipe images onto the screen. Pipe objects are created after a set number of milliseconds. The newly formed pipe is then added to the pipes group""" if timer > scaling * (1 / speed) * 1000: characteristics = spawn_pipe(image_list) if characteristics is not None: pipe = Enemy(characteristics[0], characteristics[1], characteristics[2]) group.add(pipe) return pipe
def spawn_car(config: Config, rolling_counter: int, all_sprites: pygame.sprite.Group, supervisor: Supervisor, current_time: int) -> int: rolling_counter += 1 if rolling_counter + 1 >= (framerate / config["spawn_cooldown"]): car = Car(config["car"], dir=-90, supervisor=supervisor) if pygame.sprite.spritecollideany(car, all_sprites): car.kill() return 0 all_sprites.add(car) id, res = supervisor.reserve_road(car, current_time) logging.debug(f"Spawned car: {car} with reservation {id}:{res}") if res is False: car.kill() return 0 return rolling_counter + 1
def update_aliens(ai_settings: Settings, stats: GameStats, screen: pygame.Surface, aliens: pygame.sprite.Group, ship: Ship, bullets: pygame.sprite.Group, sb: ScoreBoard) -> NoReturn: """更新外星人群中所有外星人的位置""" check_fleet_edges(ai_settings, aliens) aliens.update() # 检测外星人和飞船之间的碰撞 if pygame.sprite.spritecollide(ship, aliens, False): ship_hit(ai_settings, stats, screen, sb, ship, aliens, bullets) # 检查是否有外星人到达了屏幕底端 check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets, sb)
def update_bullets(ai_settings: Settings, stats: GameStats, screen: pygame.Surface, sb: ScoreBoard, ship: Ship, aliens: pygame.sprite.Group, bullets: pygame.sprite.Group) -> NoReturn: """更新子弹的位置,并删除已消失的子弹""" # 更新子弹的位置 bullets.update() # 删除已消失的子弹 for bullet in bullets.copy(): if bullet.rect.bottom <= 0: bullets.remove(bullet) check_bullet_alien_collisions(ai_settings, stats, sb, aliens, bullets, screen, ship)
def update(self, gold: pygame.sprite.Group) -> None: """Update the spinning animation and possibly jump.""" # Update the disappear timer and remove from group if time. self._disappear_timer += 1 if self._disappear_timer % self._disappear_time == 0: gold.remove(self) else: # Update the spinning animation. self._rotation_timer += 1 if self._rotation_timer % 3 == 0: self._current_image += 1 self.image = self._images[self._current_image % len(self._images)] loc: tuple = self.rect.topleft self.rect = self.image.get_rect() self.rect.topleft = loc
def check_fleet_edges(ai_settings: Settings, aliens: pygame.sprite.Group) -> NoReturn: """有外星人到达边缘是采取相应的措施""" for alien in aliens.sprites(): if alien.check_edges(): change_fleet_direction(ai_settings, aliens) break
def draw(sprites: pygame.sprite.Group, gas_bar: Bar, temp_bar: Bar, score: int): """ :param sprites: Group of stripes :param gas_bar: The gas bar that will be drawn :param temp_bar: The temp_bar that will be drawn :param score: The current score This function renders all sprites, bars and borders. """ WINDOW.fill(BACKGROUND_COLOR) sprites.draw(WINDOW) score_text = FONT.render(str(round(score)), True, WHITE_COLOR) WINDOW.blit(score_text, (SCREEN_SIZE[0] - score_text.get_width() - 20, 20)) gas_bar.draw(WINDOW) temp_bar.draw(WINDOW)
def update(self, frametime: int, food_group: pygame.sprite.Group): for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.KEYDOWN and event.key in self.shortcuts.keys(): event: pygame.event.Event # Prevents movement to the opposite direction(snake would collide with itself) opposites = { Direction.N: Direction.S, Direction.S: Direction.N, Direction.W: Direction.E, Direction.E: Direction.W, } direction = self.shortcuts.get(event.key) if opposites.get(self.direction) != direction: self.new_direction = direction # Using frametime keeps the movement relatively stable despite the FPS the game is running at if self.frametime_counter >= self.frametime_for_step: self.step() self.frametime_counter = 0 head: SnakeUnit = self.sprites().pop() collided_foods = pygame.sprite.spritecollide(head, food_group, dokill=True) if len(collided_foods) > 0: food_group.add(Food(self)) new_head = SnakeUnit() x_mov = self.direction.value[0] y_mov = self.direction.value[1] new_head.rect = head.rect.move(x_mov, y_mov) self.add(new_head) # Correct snake position if it is out of screen head: SnakeUnit = self.sprites().pop() if head.rect.x < 0: head.rect.x = Screen.WIDTH - head.rect.w elif head.rect.x > Screen.WIDTH - head.rect.w: head.rect.x = 0 elif head.rect.y < 0: head.rect.y = Screen.HEIGHT - head.rect.h elif head.rect.y > Screen.HEIGHT - head.rect.h: head.rect.y = 0 else: self.frametime_counter += frametime
def collision_pairs_self(grpSprites: pygame.sprite.Group, fncCollided=pygame.sprite.collide_rect) -> List[Tuple[Sprite, Sprite]]: lstPairs = [] lstSpr = grpSprites.sprites() for i in range(len(lstSpr)): for j in range(i + 1, len(lstSpr)): if fncCollided(lstSpr[i], lstSpr[j]): lstPairs.append((lstSpr[i], lstSpr[j])) return lstPairs
def SpriteGroupRect(sg: pygame.sprite.Group): if sg.__len__() > 0: minLeft = min((o.rect.left for o in sg)) minTop = min((o.rect.top for o in sg)) maxRight = max((o.rect.right for o in sg)) maxBottom = max((o.rect.bottom for o in sg)) return pygame.rect.Rect(minLeft, minTop, maxRight - minLeft, maxBottom - minTop) else: return pygame.rect.Rect(0, 0, 0, 0)
def update_keys(self, projectiles_group: pygame.sprite.Group, enemy_projectiles_group: pygame.sprite.Group): keys = pygame.key.get_pressed() # math.ceil to avoid integer truncation if keys[settings.keys["UP"]]: #print(self.rect.y) self.y -= (self.speed * settings.DELTA_T) #print(self.rect.y) self.dirty = 1 if keys[settings.keys["DOWN"]]: self.y += (self.speed * settings.DELTA_T) self.dirty = 1 if keys[settings.keys["LEFT"]]: self.x -= (self.speed * settings.DELTA_T) self.dirty = 1 if keys[settings.keys["RIGHT"]]: self.x += (self.speed * settings.DELTA_T) self.dirty = 1 if keys[settings.keys["BOMB"]]: if self.bomb_timer <= 0: enemy_projectiles_group.empty() self.bomb_timer = 10000 self.x = max(self.x, settings.LEFT_BOUND) self.x = min(self.x + self.rect.w, settings.RIGHT_BOUND) - self.rect.w self.y = max(self.y, settings.LOWER_BOUND) self.y = min(self.y + self.rect.h, settings.UPPER_BOUND) - self.rect.h self.rect.topleft = round(self.x), round(self.y) self.hitbox.topleft = utils.x_offset(self.rect, self.hitbox.w), utils.y_offset( self.rect, self.hitbox.h) if keys[settings.keys["SHOOT"]]: if self.timer > self.fire_delay: settings.sounds["effects"]["shoot"].play() self.fire(projectiles_group) self.timer = 0 self.dirty = 1
def check_aliens_bottom(ai_settings: Settings, stats: GameStats, screen: pygame.Surface, ship: Ship, aliens: pygame.sprite.Group, bullets: pygame.sprite.Group, sb: ScoreBoard) -> NoReturn: """检查是否有外星人到达了屏幕底端""" screen_rect = screen.get_rect() for alien in aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom: # 像飞船被撞到一样进行处理 ship_hit(ai_settings, stats, screen, sb, ship, aliens, bullets)
def find_angle(missiles: pygame.sprite.Group, player): missiles.update() for missile in missiles: lista = [] for num in range(2): vec = player.rect.center[num] - missile.rect.center[num] lista.append(vec) vector = pygame.math.Vector2(lista[0], lista[1]) clockwise = pygame.math.Vector2.angle_to(missile.direction, vector) if clockwise < 0: clockwise = 360 + clockwise anticlockwise = abs(360 - clockwise) if clockwise < anticlockwise: if clockwise > 10 or clockwise < -10: missile.angle_speed = 5 else: missile.angle_speed = 0 else: if anticlockwise > 10 or anticlockwise < -10: missile.angle_speed = -5 else: missile.angle_speed = 0
def check_bullet_alien_collisions(ai_settings: Settings, stats: GameStats, sb: ScoreBoard, aliens: pygame.sprite.Group, bullets: pygame.sprite.Group, screen: pygame.Surface, ship: Ship) -> NoReturn: """响应子弹和外星人的碰撞""" # 删除相应的子弹和外星人 collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) if collisions: for alien in collisions.values(): stats.score += ai_settings.alien_points * len(alien) sb.prep_score() check_high_scord(stats, sb) if len(aliens) == 0: # 删除现有的子弹并创建一群外星人 bullets.empty() ai_settings.increase_speed() # 提高等级 stats.level += 1 sb.prep_level() create_fleet(ai_settings, screen, ship, aliens)
def spawn(self, all_sprites, mobs: pg.sprite.Group) -> int: """ Spawns enemies pseudo-randomly in an 8x8 tile area centered on the Spawner. Returns count of enemies spawned. """ max_count = randint( self.settings["gen"]["spawn_min"], self.settings["gen"]["spawn_max"], ) count = 0 for row in range(self.rows - 4, self.rows + 4): for col in range(self.cols - 4, self.cols + 4): if col <= self.settings["lvl"]["tiles_wide"]: if count >= max_count: break elif self.level_data[row][col] == "." and random() < 0.25: if random() < 0.5: mob = Mob( self.settings, self.img, "sleeper", col, row, ) else: mob = Mob( self.settings, self.img, "thrall", col, row, ) all_sprites.add(mob) mobs.add(mob) count += 1 self.kill() return count
def update(self, player_projectile_group: pygame.sprite.Group, enemy_projectile_group: pygame.sprite.Group, player_group: pygame.sprite.Group, powerup_group: pygame.sprite.Group): self.fire_timer += settings.DELTA_T * 1000 self.hit_timer += settings.DELTA_T * 1000 self.update_movement() self.update_fire(enemy_projectile_group) hit_count = len(pygame.sprite.spritecollide(self, player_projectile_group, False)) if self.hit_timer > self.invuln_delay and pygame.sprite.spritecollide(self, player_projectile_group, True): self.health -= hit_count self.hit_timer = 0 if self.health <= 0: self.kill() settings.sounds["effects"]["explode"].play() for p in player_group: p.score += self.score powerups = ["heart", "speed", "firerate", "count", "spread", "invuln"] powerup = random.choices(powerups, weights=[settings.LIVES - p.health, 5 - p.p_speed_count, 5 - p.p_firerate_count, 5 - p.p_count_count, 5 - p.p_spread_count, 5 - p.invuln_count]) if random.randint(0,0) % 3 == 0: powerup_group.add(Powerup(100, self.rect.x, self.rect.y, pygame.transform.rotate(powerup_ims[powerup[0]], 90), powerup[0])) if self.is_hit(): self.image = self.image.copy() self.image.set_alpha(127) else: self.image = self.image.copy() self.image.set_alpha(255) if pygame.sprite.spritecollide(self, player_group, False): self.dirty = 1 if self.rect.right <= settings.LEFT_BOUND or self.rect.x >= settings.RIGHT_BOUND or \ self.rect.bottom <= settings.LOWER_BOUND or self.rect.y >= settings.UPPER_BOUND: self.dirty = 0