# 《外星人入侵》运行的所有函数 import sys import pygame from bullet import Bullet from alien import Alien from time import sleep import json import music def play_bg_music(): """背景音乐""" if not pygame.mixer.music.get_busy(): pygame.mixer.music.play() def check_keydown_events(event, ai_settings, screen, ship, bullets, game_stats, scoreb, aliens): """" 响应鼠标按下操作 """ # 按右箭头飞船向右移动 if event.key == pygame.K_RIGHT: ship.moving_right = True # 按左箭头飞船向左移动 elif event.key == pygame.K_LEFT: ship.moving_left = True # 按空格键创建一颗子弹并将其加入到编组bullets中 elif event.key == pygame.K_SPACE: fire_bullet(ai_settings, screen, ship, bullets) # 按p开始游戏 elif event.key == pygame.K_p: start_game(ai_settings, screen, ship, bullets, game_stats, scoreb, aliens) # 按z暂停游戏3s elif event.key == pygame.K_z: sleep(2) # 按q退出游戏并把最高分写入文件 elif event.key == pygame.K_q: with open('Max_score.json', 'w', encoding='UTF-8') as file: json.dump(game_stats.high_score, file) sys.exit() def fire_bullet(ai_settings, screen, ship, bullets): """ 按照要求发射子弹数量 """ if len(bullets) < ai_settings.bullet_allowed: music.bullet_biu() # 发射子弹的声音 new_bullet = Bullet(ai_settings, screen, ship) # 如果还没有到达限制,就发射一颗子弹 bullets.add(new_bullet) # 创建一颗子弹,并将其加入到编组bullets中 def start_game(ai_settings, screen, ship, bullets, game_stats, scoreb, aliens): """ P264中动手试一试14-1的练习:让玩家按p开始游戏 """ # 重置游戏统计信息 game_stats.reset_stats() game_stats.game_active = True # 重置记分牌图像 scoreb.prep_score() scoreb.prep_high_score() scoreb.prep_level() scoreb.prep_ships() # 清空外星人列表和子弹列表 aliens.empty() bullets.empty() # 创建一群新的外星人,并让飞船居中 create_fleet(ai_settings, screen, ship, aliens) ship.center_ship() # 暂停让用户反应一会 sleep(0.5) def check_keyup_events(event, ship): """" 响应鼠标松开---飞船停下 """ if event.key == pygame.K_RIGHT: ship.moving_right = False elif event.key == pygame.K_LEFT: ship.moving_left = False def check_play_button(ai_settings, screen, game_stats, scoreb, play_button, ship, aliens, bullets, mouse_x, mouse_y): """ 在玩家单击Play按钮时开始游戏 """ button_clicked = play_button.button_rect.collidepoint(mouse_x, mouse_y) # 单击Play按钮且游戏处于非活跃状态时----避免了游戏处于活跃状态下单击到了Play按钮区域重启游戏 if button_clicked and not game_stats.game_active: """如果鼠标单击位置在msg_image_rect范围内则将游戏置于活跃状态""" # # 重置游戏设置 ai_settings.initialize_dynamic_settings() # 游戏开始后Play按钮隐藏起来 pygame.mouse.set_visible(False) start_game(ai_settings, screen, ship, bullets, game_stats, scoreb, aliens) def check_events(ai_settings, screen, game_stats, scoreb, play_button, ship, aliens, bullets): """ 响应鼠标和键盘事件 """ # 游戏退出并把最高分写入文件 for event in pygame.event.get(): if event.type == pygame.QUIT: with open('Max_score.json', 'w', encoding='UTF-8') as file: json.dump(game_stats.high_score, file) sys.exit() # 响应Play按钮操作 elif event.type == pygame.MOUSEBUTTONDOWN: mouse_x, mouse_y = pygame.mouse.get_pos() # 该函数返回一个元组--获取鼠标单击Play按钮时的位置 check_play_button(ai_settings, screen, game_stats, scoreb, play_button, ship, aliens, bullets, mouse_x, mouse_y) # 判读飞船向左还是向右移动 elif event.type == pygame.KEYDOWN: check_keydown_events(event, ai_settings, screen, ship, bullets, game_stats, scoreb, aliens) # 飞船停下 elif event.type == pygame.KEYUP: check_keyup_events(event, ship) def update_screen(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets, play_button): """ 更新屏幕上的图像并切换到新屏幕 """ # 每次循环时都重绘屏幕 screen.fill(ai_settings.bg_color) # 先填充背景后绘制飞船 ship.blitem() aliens.draw(screen) # 在飞船后重绘所有子弹 for bullet in bullets.sprites(): bullet.draw_bullet() # 显示得分 scoreb.show_score() # 如果游戏处于非活动状态就绘制Play按钮 if not game_stats.game_active: play_button.draw_button() # 让最近绘制的屏幕可见 pygame.display.flip() def start_new_level(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets): """ 当消灭干净外星人提高一个等级 """ if len(aliens) == 0: # 删除现有子弹 bullets.empty() # 逐渐提高速度加快游戏节奏 ai_settings.increase_speed() # 当前屏幕外星人全部被消灭就提高一个等级 game_stats.level += 1 scoreb.prep_level() # 创建一群新的外星人 create_fleet(ai_settings, screen, ship, aliens) # 调用创建外星人群的函数 def check_bullet_alien_collisions(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets): """子弹与外星人相撞后的操作""" # 检查是否有子弹击中外星人 # 如果击中了就删除相应的子弹与外星人 collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) """方法sprite.groupcollide()检查两个编组的成员之间的碰撞(碰撞是指游戏元素重叠在一起): 将每颗子弹同每个外星人的rect作比较 并返回一个字典 字典中的键为子弹 值为被击中的外星人""" # 每消灭一个外星人都将加一个points且显示最新得分的图像 if collisions: music.voice_small() # 子弹与外星人相撞的声音 for aliens in collisions.values(): # aliens指被同一颗子弹击中的外星人---是一个列表 game_stats.score += ai_settings.alien_points * len(aliens) scoreb.prep_score() check_high_score(game_stats, scoreb) start_new_level(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets) def update_bullets(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets): """ 更新子弹位置并删除已消失的子弹 """ # 更新子弹位置 bullets.update() # 删除已消失的子弹 for bullet in bullets.copy(): if bullet.rect.bottom <= 0: # 当子弹底部越过屏幕顶部(0)时删除子弹 bullets.remove(bullet) check_bullet_alien_collisions(ai_settings, screen, game_stats, scoreb, ship, aliens, bullets) def get_number_aliens_X(ai_settings, alien_width): """ 计算每行可容纳多少个外星人 """ availabble_space_x = ai_settings.screen_width - 2 * alien_width # 一行可可容纳的水平长度 number_aliens_x = int(availabble_space_x / (2 * alien_width)) # 一行可容纳多少个外星人 return number_aliens_x def get_number_rows(ai_settings, alien_height, ship_height): """ 计算屏幕可容纳多少行外星人 """ availables_space_y = (ai_settings.screen_height-ship_height- (3*alien_height)) number_rows = int(availables_space_y / (2 * alien_height)) return number_rows def create_alien(ai_settings, screen, aliens, alien_number, row_number): """ 创建一个外星人并将其放在当前行 """ alien = Alien(ai_settings, screen) alien_width = alien.rect.width alien_height = alien.rect.height + 3 # 让外星人之间间隔大些 alien.x = alien_width + 2 * alien_width * alien_number # 获取新建外星人所移动的位置 alien.rect.x = alien.x # 新建外星人的位置 alien.rect.y = alien_height + 2 * alien_height * row_number # 新行的位置 aliens.add(alien) def create_fleet(ai_settings, screen, ship, aliens): """ 创建外星人群 """ # 创建一个外星人并计算一行可容纳多少个外星人 # 外星人间距为外星人的宽度 alien = Alien(ai_settings, screen) number_aliens_x = get_number_aliens_X(ai_settings, alien.rect.width) # 一行可容纳外星人的个数 number_rows = get_number_rows(ai_settings, alien.rect.height, ship.rect.height) # 屏幕上可容纳外星人的行数 # 内外双循环创建外星人群 for row_number in range(number_rows): # 外循环创建外星人行数 for alien_number in range(number_aliens_x): # 内循环创建外星人 create_alien(ai_settings, screen, aliens, alien_number, row_number) # 调用创建外星人的函数 def check_fleet_edges(ai_settings, aliens): """ 有外星人到达边缘时采取相应的措施 """ for alien in aliens.sprites(): if alien.check_edges(): change_fleet_direction(ai_settings, aliens) break def change_fleet_direction(ai_settings, aliens): """ 将整全外星人下移并改变它们的方向 """ for alien in aliens.sprites(): alien.rect.y += ai_settings.fleet_drop_speed ai_settings.fleet_direction *= -1 def check_aliens_bottom(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets): """检测外星人是否到达屏幕底部""" screen_rect = screen.get_rect() for alien in aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom: # 外星人触底爆炸声 music.voice_large() # 有外星人到达屏幕后进行像飞船被撞后一样的操作 ship_aliens_hit(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets) break def ship_aliens_hit(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets): """ 响应外星人飞船相撞的后续操作 """ # 外星人飞船相撞时 发出碰撞声音 ship_left减1 if game_stats.ships_left > 0: music.voice_large() game_stats.ships_left -= 1 # 更新屏幕上飞船的艘数 scoreb.prep_ships() else: game_stats.game_active = False ai_settings.increase_wen() # 游戏结束后alien的速度得回到最初为 pygame.mouse.set_visible(True) # 游戏结束后Play按钮显示出来 # 清空外星人列表和子弹列表 aliens.empty() bullets.empty() # 创建一群新的外星人并将飞船重新出现在屏幕在底部中央 create_fleet(ai_settings, screen, ship, aliens) ship.center_ship() # 暂停让用户反应一会 sleep(0.5) def update_aliens(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets): """ 更新外星人群中所有外星人的位置 """ check_fleet_edges(ai_settings, aliens) aliens.update() if pygame.sprite.spritecollideany(ship, aliens): """ 接收俩个实参--检测飞船和外星人是否发生碰撞:发生了---往下走;没发生---返回None """ ship_aliens_hit(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets) # 检测是否有外星人到达屏幕底部 check_aliens_bottom(ai_settings, game_stats, scoreb, screen, ship, aliens, bullets) def check_high_score(game_stats, scoreb): """检查是否诞生了新的最高得分""" if game_stats.score > game_stats.high_score: game_stats.high_score = game_stats.score scoreb.prep_high_score()