不知不觉,我用了差不多一周的时间将《Python编程—从入门到实践》中的第二部分的第一个项目:《外星人入侵》游戏大致过了一遍。在今天开始的博客中,我将简单回顾一下这个程序,让自己更清楚这个项目的组织结构。
1. game_functions:
文件game_functions.py中包含一系列函数,游戏的大部分工作都是由它们完成的。其存储着大量让游戏《外星人入侵》运行的函数。通过创建模块game_functions ,可避免alien_invasion.py太长,并使其逻辑更容易理解,以下是该文件中的所有函数(共18个):
(1) check_keydown_events():
def check_keydown_events(event, ai_settings, screen, ship, bullets):\"\"\"Respond to keypresses.\"\"\"if event.key == pygame.K_RIGHT:ship.moving_right = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_SPACE: #创建一颗子弹,并将其加入到编组bullets中fire_bullet(ai_settings, screen, ship, bullets)elif event.key == pygame.K_q:sys.exit()
可以看出,这是一个响应用户按下按键这个事件的函数,其中共检查了四个具体按键:右箭头键、左箭头键、空格键和Q键,它们功能分别是将飞船向右、左移动,开火发射子弹,退出游戏。
(2) check_keyup_events():
def check_keyup_events(event, ship):\"\"\"Respond to key releases.\"\"\"if event.key == pygame.K_RIGHT:ship.moving_right = Falseelif event.key == pygame.K_LEFT:ship.moving_left = False
同样,这是一个响应用户松开按键这个事件的函数。其中共检查了两个具体按键:右箭头键和左箭头键,它们功能分别是将飞船停止向右、左移动。
(3) check_events():
def check_events(ai_settings, screen, stats, play_button, ship, aliens, bullets, ):\"\"\"Respond to keypresses and mouse events.\"\"\"for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()elif event.type == pygame.KEYDOWN:check_keydown_events(event, ai_settings,screen, ship, bullets)elif event.type == pygame.KEYUP:check_keyup_events(event, ship)elif event.type == pygame.MOUSEBUTTONDOWN:mouse_x, mouse_y = pygame.mouse.get_pos()check_play_button(ai_settings, screen, stats, play_button, ship,aliens, bullets,mouse_x, mouse_y)
这个函数则是检查用户按键或鼠标事件的函数。它检查了四种事件:若玩家点击了pygame的关闭键,游戏便会退出;若玩家按下了键盘上的某个按键,便会调用
check_keydown_events()
这个函数;若玩家松开了某个按键,则调用
check_keyup_events()
;若玩家按下了鼠标上的某个按键,则会检查按的位置是不是在 “Play” 按键的位置。
(4)check_play_button():
def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y):button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)if button_clicked and not stats.game_active:#仅当玩家单击了Play按钮且 游戏当前处于非活动状态时,游戏才重新开始stats.reset_stats()# 重置游戏统计信息stats.game_active = True #这个函数的代码执行完毕后,游戏就会开始ai_settings.initialize_dynamic_settings() #重置游戏设置aliens.empty() #清空外星人列表列表bullets.empty() #清空子弹列表# 创建一群新的外星人,并让飞船居中create_fleet(ai_settings, screen, ship, aliens)ship.center_ship()
这个函数让玩家通过点击 “Play” 按钮来开始游戏并重置游戏设定。其中,第45行的 if 语句确认玩家点击了 “Play” 并且游戏处于非活动状态。确认完毕后,便会将游戏设置成活动状态并重置该游戏的各项设定(见第49-55行)。
(5)update_screen():
def update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets, play_button):screen.fill(ai_settings.bg_color) #每次循环都重绘屏幕for bullet in bullets:bullet.draw_bullet() #绘制子弹ship.blitme() #绘制飞船aliens.draw(screen)#绘制外星人sb.show_score() #显示得分if not stats.game_active: # 如果游戏处于非活动状态,就绘制Play按钮play_button.draw_button()pygame.display.flip() #不断更新屏幕,以显示元素的新位置
这个函数主要负责屏幕中各项元素的绘制。包括了子弹,飞船和外星人,并且在屏幕上显示了玩家的得分与非活动状态时的 “Play” 按钮。不断更新屏幕,以显示元素的新位置。
(6)update_bullets():
def update_bullets(ai_settings,screen, stats, sb, ship,aliens,bullets):bullets.update()# 更新子弹的位置for bullet in bullets.copy(): # 删除已消失的子弹if bullet.rect.bottom <= 0:bullets.remove(bullet)check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets)
这个函数则对屏幕上的子弹进行实时更新。位于第75行的 for 语句用来删除已经消失的子弹,而第79行则调用了
check_bullet_alien_collisions()
来检查子弹和外星人的碰撞。
(7)check_bullet_alien_collisions():
def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets):collisions = pygame.sprite.groupcollide(bullets, aliens, True ,True)# 检查是否有子弹击中了外星人,如果是这样,就删除相应的子弹和外星人if collisions:stats.score += ai_settings.alien_points #将得分加上一个外星人值的点数sb.prep_score() #创建一幅显示最新得分的新图像check_high_score(stats, sb)if len(aliens) == 0:# 删除现有的子弹并新建一群外星人bullets.empty()ai_settings.increase_speed()#在整群外星人都被消灭后调用increase_speed()来加快游戏的节奏create_fleet(ai_settings, screen, ship, aliens)
这个函数检查了外星人和子弹的碰撞。第83行语句调用了
pygame.sprite.groupcollide()
来检查是否有子弹击中了外星人,如果是这样,就删除相应的子弹和外星人,并将得分加上一个外星人值的点数,然后创建一幅显示最新得分的新图像。若所有外星人都被消灭完,就删除现有的子弹并新建一群外星人。在整群外星人都被消灭后调用
increase_speed()
来加快游戏的节奏。
(8)fire_bullet():
def fire_bullet(ai_settings,screen,ship,bullets):if len(bullets) < ai_settings.bullets_allowed: #检查bullets的长度。如果len(bullets)小于4,我们就创建一个新子弹new_bullet = Bullet(ai_settings, screen, ship)bullets.add(new_bullet)
该函数检查了子弹的数量并创建新的子弹。若子弹数小于要求值,就创建一个新的子弹到编组中。
(9)create_fleet():
\"\"\"创建外星人群\"\"\"alien = Alien(ai_settings, screen)number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)number_rows = get_number_rows(ai_settings, ship.rect.height, alien.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)
这个函数主要用来创建外星人群。在第104行处首先创建了一个外星人,接着,计算了每行能装多少个外星人,一共能装几行外星人。最后,在第108-110行中,利用了 for 循环来创建外星人群。
(10)get_number_aliens_x():
def get_number_aliens_x(ai_settings, alien_width):available_space_x = ai_settings.screen_width - 2 * alien_widthnumber_aliens_x = int(available_space_x /(2 * alien_width))return number_aliens_x
这个函数用来计算可用于放置外星人的水平空间,以及其中可容纳多少个外星人。最后返回了该值用于
create_fleet()
。
(11)get_number_rows():
def get_number_rows(ai_settings, ship_height, alien_height):\"\"\"计算屏幕可容纳多少行外星人\"\"\"available_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height)number_rows = int(available_space_y / (2 * alien_height))return number_rows
这个函数可以计算屏幕可容纳多少行外星人。通过屏幕、飞船和相关其他要求的高度计算出可用的纵向空间(见第133行)。接着利用该值求出具体的外星人行数。
(12)create_alien():
def create_alien(ai_settings,screen,aliens,alien_number,row_number):alien = Alien(ai_settings, screen)alien_width = alien.rect.widthalien.x = alien_width + 2 * alien_width * alien_numberalien.rect.x = alien.xalien.rect.y = alien.rect.height + 2 * alien.rect.height * row_numberaliens.add(alien)
这个函数用于创建新的外星人。其中的代码得到了每个外星人所处的空间位置并将每个新创建的外星人都添加到编组
aliens
中。
(13)check_fleet_edges():
def check_fleet_edges(ai_settings,aliens):\"\"\"有外星人到达边缘时采取相应的措施\"\"\"for alien in aliens.sprites():if alien.check_edges():change_fleet_direction(ai_settings,aliens)break
该函数在有外星人到达边缘时采取相应的措施。可以看出,在第140行的 if 语句检查了外星人是否碰到边缘,若碰到了,就变换外星人的移动方向。