内容
本文重点介绍game_functions.py模块,其中存储了各个模块间的交互行为和游戏的运行逻辑。
回顾
回顾一下主模块alien.invasion.py中的循环代码块
def run_game():
'''初始化游戏并创建一个屏幕对象'''
#初始化pygame,设置屏幕对象
#-----snip----------
#创建一艘飞船
ship = Ship(ai_settings,screen)
#创建一个用于存储子弹的编组,以便能够管理所有发射出去的子弹
bullets = Group()
#创建一个外星人编组
aliens = Group()
#创建外星人群
gf.create_fleet(ai_settings,screen,ship,aliens)
while True:
gf.check_events(ai_settings,screen,stats,sb,play_button,ship,aliens,bullets)#检查用户输入
if stats.game_active:
#更新飞船位置
ship.update()
gf.update_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets)#更新子弹位置
gf.update_aliens(ai_settings,screen,stats,sb,ship,aliens,bullets)
gf.update_screen(ai_settings,screen,stats,sb,ship,aliens,bullets,play_button)
1.初始化一艘飞船:ship=Ship(screen)
——加载’images\ship.bmp’路径中的飞船图像,在gf.update_screen()方法中调用飞船对象的ship.blitme()方法经行图像绘制。
ps:位置参数#将飞船放在屏幕底部中间
self.rect.centerx = self.screen_rect.centerx#屏幕矩形的中间坐标值
self.rect.bottom = self.screen_rect.bottom#屏幕底部的坐标值
2.控制飞船移动
在主循环中使用事件检测机制(调用gf.check_events()方法),当有←/→/↑/↓方向键按下时,设置飞船对象相应的移动方向为True
if event.key == pygame.K_RIGHT: #→键按下
#向右移动飞船
ship.moving_right = True
elif event.key == pygame.K_LEFT: #←键按下
#向左移动飞船
ship.moving_left = True
elif event.key == pygame.K_UP:#↑键按下
ship.moving_up = True
elif event.key == pygame.K_DOWN:#↓键按下
ship.moving_down = True
根据移动方向,改变飞船坐标位置(调用飞船对象中的方法),同时注意检测飞船移动范围不能超过游戏界面的范围。
def update(self):
'''根据移动标志调整飞船位置'''
if self.moving_right and self.rect.right < self.screen_rect.right:#检查是否超出屏幕范围(右边界)
# self.rect.centerx +=1
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0: #此时两个按键同时按下的话飞船保持不动 #检查是否超出屏幕范围(左边界)
# self.rect.centerx -=1
self.center -= self.ai_settings.ship_speed_factor
if self.moving_up and self.bottom > self.rect.height: #此时两个按键同时按下的话飞船保持不动 #检查是否超出屏幕范围(上边界)
# self.rect.centerx -=1
self.bottom -= self.ai_settings.ship_speed_factor
if self.moving_down and self.rect.bottom < self.screen_rect.bottom: #此时两个按键同时按下的话飞船保持不动 #检查是否超出屏幕范围(下边界)
# self.rect.centerx -=1
self.bottom += self.ai_settings.ship_speed_factor
#根据self.center跟新rect对象
self.rect.centerx = self.center
self.rect.bottom = self.bottom
相应的,当某个方向键松开后也要对相应的移动方向进行“清除”处理
'''响应键松开'''
if event.key == pygame.K_RIGHT: #→键松开
ship.moving_right = False
elif event.key == pygame.K_LEFT: #←键松开
ship.moving_left = False
elif event.key == pygame.K_UP:#↑键按下
ship.moving_up = False
elif event.key == pygame.K_DOWN:#↓键按下
ship.moving_down = False
更新完飞船的坐标后,再调用update()方法就可以在屏幕刷新飞船的新位置了
self.rect.centerx = self.center
self.rect.bottom = self.bottom
3.创建外星人
初始化部分调用了gf.create_fleet()创造了一群规则排列的外星人
def create_fleet(ai_settings,screen,ship,aliens):
'''创建外星人群'''
alien = Alien(ai_settings,screen)
alien_width = alien.rect.width
# avaliable_space_X = ai_settings.screen_width - 2*alien_width#屏幕两边留空
# number_aliens_x = int(avaliable_space_X / (2*alien_width))#一行中可以排布的外星人数量
#等价于下面重构的函数
number_aliens_x = get_bumber_aliens_X(ai_settings,alien_width) #一行有多少个外星人
number_rows = get_bumber_rows(ai_settings,ship.rect.height,alien.rect.height)#有多少行外星人
#创建外星人群体
#创建第一行外星人
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
# #创建一个外星人并将其加入当前行
# alien = Alien(ai_settings,screen)
# alien.x = alien_width+2*alien_width*alien_number
# alien.rect.x = alien.x
# aliens.add(alien)
#等价于下面重构的函数
create_alien(ai_settings,screen,aliens,alien_number,row_number)
首先创建一个外星人以获取其宽度,然后计算屏幕可以容纳多少行,列的外星人数量并以此构建外星人群体(注意留出一部分飞船的移动空间)
avaliable_space_X = ai_settings.screen_width - 2*alien_width
avaliable_space_y = (ai_settings.screen_height-(3*alien_height)-ship_height)
每个外星人坐标的设置
alien.x = alien_width+2*alien_width*alien_number
alien.rect.x = alien.x
alien.rect.y = alien.rect.height +2* row_bumber * alien.rect.height
3.控制外星人的移动
外星人的移动规则很简单,初始化后向右移动,一旦有外星人碰到界面的右边界则整体向下移动,然后向左移动,同理,一旦有外星人碰到界面左边界则整体继续向下移动,然后向右移动,依次反复进行。
分析:游戏外星人的移动方向可以简记为 fleet_direction(+1==>右移动,-1==>左移动)
所以对外星人位置的更新实现为:
对x坐标值更新:
def update(self):
'''向左/右移动外星人'''
# self.x += self.ai_settings.alien_speed_factor#移动速度
self.x += (self.ai_settings.alien_speed_factor*self.ai_settings.fleet_direction)
self.rect.x = self.x
对y坐标值更新:(只有当有外星人触碰到游戏边界时才会发生)
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_fleet_edges(ai_settings,aliens):
'''有外星人到达边缘时采取相应的措施'''
for alien in aliens.sprites():
if alien.check_edges():#检测该外星人是否达到边缘
change_fleet_direction(ai_settings,aliens)#改变移动方向
break
同样的,更新完每个外星人的x,y坐标后,对群组aliens调用aliens.draw(screen)#在屏幕上绘制编组中的每一个外星人,实现外星人位置的更新。
4.飞船的射击行为
设计功能“玩家按空格键时发射子弹(小矩形),子弹在屏幕中向上穿行,碰到外星人,或者抵达屏幕上边界后消失
当检测到空格按下时,创建一个子弹实例
elif event.key == pygame.K_SPACE:#按下空格
fire_bullet(ai_settings,screen,ship,bullets)
def fire_bullet(ai_settings,screen,ship,bullets):
'''如果子弹数量未达到限制,则发射一颗子弹'''
#创建一个新的子弹对象并存储到bullets中
if len(bullets) < ai_settings.bullets_allowed:#子弹数目限制
new_bullet = Bullet(ai_settings,screen,ship)#创建一个子弹实例
bullets.add(new_bullet)#将子弹实例添加到子弹群组中
注意子弹实例在创建时会记录当前飞船的位置:
bullet.py
#将子弹移到正确的位置上
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
子弹射出后,只能向上移动
def update(self):
'''向上移动子弹'''
self.y -=self.speed_factor
self.rect.y = self.y #更新子弹的位置
更新子弹坐标的方法
def update_bullets(ai_settings,screen,stats,sb,ship,aliens,bullets):
'''更新子弹的位置后立即检测是否与外星人发生碰撞,并删除消失的子弹'''
#更新子弹的位置
bullets.update()#对编组调用update()方法时,会对每个成员都调用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)
其中,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)
#解析:便利编组中的每一颗子弹,再遍历编组中的每一个外星人,当有子弹和外星人的Rect重叠时,返回一个字典:键为子弹,值为碰撞的外星人[一个列表],后面两个参数TRUE指删除发生碰撞的子弹和外星人
if collisions:
for aliens in collisions.values():
stats.score += ai_settings.alien_points * len(aliens)
sb.prep_score()
check_high_score(stats,sb)
if len(aliens) == 0:#外星人被消灭完了,提升游戏等级和难度,开始新的一轮游戏
start_new_level(ai_settings,screen,stats,sb,ship,aliens,bullets)
5.游戏结束的标志
游戏完结的情况:1.飞船与外星人碰撞2.外星人触碰到屏幕底端边界,同时每个玩家有三辆飞船,当飞船用完后,游戏完全结束。
1+2:出现1,2或任意一种情况都表示当前的飞船被击落了,调用ship_hit()方法进行界面重置,并更新剩余的飞船数量,当可用飞船数量为0时,游戏结束,设置游戏为非活跃状态(game_active=False)
if pygame.sprite.spritecollideany(ship,aliens):#发生碰撞,飞船被击落--
#解析spritecollideany()检查编组成员是否与精灵发生重叠,返回找到的发生碰撞的第一个外星人
# print('Ship hit!')#发生碰撞进行一系列处理
ship_hit(ai_settings,screen,stats,sb,ship,aliens,bullets)
check_aliens_bottom(ai_settings,screen,stats,sb,ship,aliens,bullets)#检查外星人到达底端
def check_aliens_bottom(ai_settings,screen,stats,sb,ship,aliens,bullets):
'''检查是否有外星人到达了屏幕底端'''
screen_rect = screen.get_rect()
for alien in aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:#外星人抵达屏幕下界
ship_hit(ai_settings,screen,stats,sb,ship,aliens,bullets)#重置游戏
break#只要有一个外星人到达屏幕底端就可以推出for循环了
def ship_hit(ai_settings,screen,stats,sb,ship,aliens,bullets):
'''响应被外星人撞到的飞船,清空子弹和外星人,重新开始游戏'''
# stats.ships_left -=1
if stats.ships_left > 0:
stats.ships_left -=1
#跟新飞船剩余数量
sb.prep_ships()
#清空外星人和子弹列表
aliens.empty()
bullets.empty()
create_fleet(ai_settings,screen,ship,aliens)
ship.center_ship()#将飞船放到屏幕底端中央
sleep(0.5)#暂停一下
else:
stats.game_active = False#飞船用完后,游戏结束
pygame.mouse.set_visible(True)#让鼠标显现出来
6.其他的装饰部分
该项目还包含了:当前得分、历史最高分、可用飞船数量,游戏难度等级的可视化显示部分以及游戏开始按钮的点击检测,但不是关键先省略之,详细内容可参考上传到csdn上的代码,附带详细的注释和解析。
附上最终的游戏截图: