项目代码如下:
settings.py
#创建一个游戏设置的类
class Settings:
def __init__(self):
#储存游戏初始化数据
#初始化游戏的静态设置
self.screen_width = 1400
self.screen_height = 750
self.bg_color = (200,200,200)
#设置飞船数量
self.ship_limit = 3
#创建关于子弹的属性
self.bullet_width = 15
self.bullet_height = 30
self.bullet_bg_color = (60,0,0)
#设置限制子弹数量
self.bullets_allowed = 3
#设置外星人下降值
self.alien_drop_factor = 2
#设置速度提升倍数
self.speedup_scale = 1.1
#设置外星人点数的提高速度
self.score_scale = 1.5
#初始化速度值
self.initialize_dynamic_settings()
def initialize_dynamic_settings(self):
#初始化动态设置
# 设置外星人移动速度
self.alien_speed_factor = 0.5
# 设置外星人群移动值,向右为1,向左为-1
self.fleet_direction = 1
#设置外星人分数
self.alien_points = 50
#设置子弹移动速度
self.bullet_speed_factor = 5
# 设置飞船移动速度
self.ship_speed_factor = 3
def increase_speed(self):
#提升速度值
self.ship_speed_factor *= self.speedup_scale
self.bullet_speed_factor *= self.speedup_scale
self.alien_speed_factor*= self.speedup_scale
#提升分数
self.alien_points = int(self.alien_points * self.score_scale)
alien.py
#创建一个关于外星人的模块
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
'''表示单个外星人的类'''
def __init__(self,ai_settings,screen):
#继承精灵类
super().__init__()
self.ai_settings = ai_settings
self.screen = screen
#返回外星人图像并矩形化
self.image = pygame.image.load('image/humor.png')
self.rect = self.image.get_rect()
#每个外星人最初都在屏幕左上角附近
self.rect.x = self.rect.width
self.rect.y = self.rect.height
#储存外星人的准确位置
self.x = float(self.rect.x)
def blitme(self):
'''在指定位置绘制外星人'''
self.screen.blit(self.image,self.rect)
def update(self):
#外星人坐标为速度乘以方向值,当方向值为负时方向改变
self.x += (self.ai_settings.alien_speed_factor *
self.ai_settings.fleet_direction)
self.rect.x = self.x
'''当方向值为1时,x 坐标增加,向右移动。方向值为-1时,x 坐标减少,向左移动'''
def check_edges(self):
#检查外星人是否碰到了边缘
#矩形化屏幕
screen_rect = self.screen.get_rect()
#当外星人贴图右边缘大于或等于屏幕矩形右边缘,返回正确
if self.rect.right >= screen_rect.right:
return True
#当外星人贴图左边缘小于或等于屏幕矩形左边缘(小于等于0),返回正确
elif self.rect.left <= screen_rect.left:
return True
bullet.py
#创建子弹类
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
'''一个对飞船发射的子弹进行管理的类'''
def __init__(self,ai_settings,screen,ship):
#通过函数super()来继承sprite
super().__init__()
self.screen = screen
#在(0,0)处创建一个代表子弹的矩形,再设置正确的位置,参数为初识坐标,子弹的宽和高
self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
#根据飞船位置来确定子弹位置
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
#储存用小数表示的子弹位置
'''由于子弹是直线向下移动,所以我们只考虑在y轴上坐标的变化,
而x轴的坐标是固定的,这由发射子弹时飞船的x轴坐标决定,
因为我们在前面定义了self.rect.centerx = ship.rect.centerx'''
self.y = float(self.rect.y)
#储存子弹颜色
self.color = ai_settings.bullet_bg_color
#储存速度
self.speed_factor = ai_settings.bullet_speed_factor
def update(self):
#让子弹向上移动
self.y -= self.speed_factor
#更新子弹rect的位置
self.rect.y = self.y
def draw_bullet(self):
#在屏幕上绘制子弹
pygame.draw.rect(self.screen,self.color,self.rect)
ship.py
import pygame
from pygame.sprite import Sprite
class Ship(Sprite):
def __init__(self,ai_settings,screen):
'''初始化飞船并设置其初始位置'''
#继承精灵
super().__init__()
self.screen = screen
self.ai_settings = ai_settings
#加载飞船图像,并获取其外接矩形
#load返回贴图所在文件
self.image = pygame.image.load('image/shot.PNG')
#矩形属性rect为贴图的矩形对象
#get_rect()是一个处理矩形图像的方法,返回值包含矩形的居中属性( center centerx centery )
#get_rect须加上(),否则后续程序在运行时会出现无法引用centerx和bottom的错误
self.rect = self.image.get_rect()
#先将表示屏幕的矩形储存在属性screen—rect中
self.screen_rect = screen.get_rect()
'''将每艘新飞船放在屏幕底部中央'''
#再将self.rect.centerx设置为表示屏幕的矩形属性centerx
#再将self.rect.bottom设置为表示屏幕的矩形属性bottom
#后面使用这个rect属性来放置飞船在屏幕底部中间
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
#在飞船属性center中储存小数点
self.center = float(self.rect.centerx)
#添加属性,设置一个飞船向右移动的标志
self.moving_right = False
#添加一个飞船向左移动的标志
self.moving_left = False
def blitme(self):
#方法blit 位块传输 将指定的像素内容传输到指定位置
self.screen.blit(self.image,self.rect)
def update(self):
#根据标志来向右移动飞船
#更新飞船的center值而不是rect(rect已被浮点化储存到center中)
'''添加条件,防止飞船移动到屏幕外'''
#以屏幕矩形的右边界为界,当按键事件(标志正确)以及飞船外接矩形坐标小于右边界时可向右移动
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
#根据标志向左移动飞船
#以屏幕矩形的左边界为准,即x轴坐标的0,当按键事件(标志正确)以及飞船外接矩形坐标大于0时可向左移动
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
'''此处使用两个if来应对左右方向按键,两个条件同时检测,当同时按下左右键时,飞船纹丝不动,
这有利于精准控制,如使用if—elif格式的话,if优先,故右键优先,同时按两个键时无法同时抵消,则向右移动'''
#根据center来更新rect
self.rect.centerx = self.center
def center_ship(self):
#让飞船底部居中
self.center = self.screen_rect.centerx
game_stats.py
#创建游戏统计类
class GameStats():
#跟踪游戏的统计信息
def __init__(self,ai_settings):
#初始化统计信息
self.ai_setting = ai_settings
#设置结束游戏的标志
#修改标志,让游戏一开始处于非活动状态
self.game_active = False
#设置最高分,最高分不会被重置,所以在init初始化
self.high_score = 0
#在初始化init中调用方法reset_stats
#在创建实例时能妥善地设置统计信息
#在后续也可以调用
self.reset_stats()
def reset_stats(self):
#重置统计
#初始化游戏运行期间可能变化的统计信息
#储存飞船数量
self.ships_left = self.ai_setting.ship_limit
#初始化得分
self.score = 0
#初始化等级
self.level = 1
button.py
#创建按钮类
#导入模块ftfont(font),它能将文本渲染到屏幕上
import pygame.ftfont
class Button():
def __init__(self,ai_settings,screen,msg):
#初始化
self.screen = screen
self.screen_rect = screen.get_rect()
#设置按钮尺寸和颜色
self.wdith,self.height = 200,50
self.button_color = (0,50,0)
#指定文本颜色
self.text_color = (255,255,255)
#None 指定了使用默认字体渲染文本,48为字号
self.ftfont = pygame.ftfont.SysFont(None,48)
#创建一个rect对象
self.rect = pygame.Rect(0,0,self.wdith,self.height)
#rect对象位置居中
self.rect.center = self.screen_rect.center
#调用按钮标签(只需创建一次)
self.prep_msg(msg)
def prep_msg(self,msg):
#创建渲染文本方法
'''将msg渲染为图像,并使其在按钮上居中'''
#将文本渲染为图像,第一个实参为文本,第二个实参为布尔值(用于指定图像边缘是否开启反锯齿功能,此处的Ture为开启)
#第三个实参为文本颜色,第四个实参为按钮颜色(即图像的背景色,当没有指定时为透明)
self.msg_image = self.ftfont.render(msg,True,self.text_color,self.button_color)
#矩形化文本图像
self.msg_image_rect = self.msg_image.get_rect()
#文本图像位置居中,即在按钮中居中(按钮矩形的中央位置)
self.msg_image_rect.center = self.rect.center
def draw_button(self):
#绘制一个用颜色填充的按钮,再绘制文本
self.screen.fill(self.button_color,self.rect)
self.screen.blit(self.msg_image,self.msg_image_rect)
scorebroad.py
import pygame.ftfont
from pygame.sprite import Group
from ship import Ship
#导入json用于写入最高分
import json
#创建计分板类
class Scoreboard():
def __init__(self,screen,ai_settings,stats):
#初始化得分涉及的属性
self.screen = screen
self.screen_rect = self.screen.get_rect()
self.ai_settings = ai_settings
self.stats = stats
#设置计分板的字体
self.text_color = (30,30,30)
#默认字体,48字号
self.ftfont = pygame.ftfont.SysFont(None,48)
#准备初始得分图像和最高分图像、等级、飞船剩余图像
self.prep_images()
def prep_images(self):
# 整合初始化图像内容
self.prep_score()
self.prep_high_score()
self.prep_level()
self.prep_ships()
def prep_score(self):
'''将得分转换为渲染的图像'''
# 得分为得分为10的整数倍,并将逗号用作千分位分隔符
rounded_score = int(round(self.stats.score, -1))
score_str = "{:,}".format(rounded_score)
self.image = self.ftfont.render(score_str,True,self.text_color,self.ai_settings.bg_color)
#将得分放在屏幕右上角
#将文字渲染成的图像矩形化,指定位置
self.score_rect = self.image.get_rect()
self.score_rect.right = self.screen_rect.right - 20
self.score_rect.top = 20
def prep_high_score(self):
'''将最高得分渲染为图像'''
#打开json文件读取最高分来圆整规范以及渲染为图像,当出现 FileNotFoundError 异常时创建json文件,并写入初始化最高分
# (这一步仅需执行一次,也可应对文件丢失情况)
try:
with open('high_score.json') as f_obj:
high_score_json = json.load(f_obj)
except FileNotFoundError:
with open('high_score.json','w') as f_obj:
json.dump(self.stats.high_score,f_obj)
# 最高得分为10的整数倍,并将逗号用作千位分隔符
high_score = int(round(high_score_json,-1))
high_score_str = "{:,}".format(high_score)
self.high_score_image = self.ftfont.render(high_score_str,True,self.text_color,self.ai_settings.bg_color)
#矩形化图像,并指定位置为屏幕顶端中央
self.high_score_rect = self.high_score_image.get_rect()
self.high_score_rect.centerx = self.screen_rect.centerx
self.high_score_rect.top = self.score_rect.top
def prep_level(self):
'''将等级转化为渲染的图像'''
self.level_image = self.ftfont.render(str(self.stats.level),True,self.text_color,self.ai_settings.bg_color)
#将等级放在得分下方
self.level_rect = self.level_image.get_rect()
self.level_rect.right = self.score_rect.right
self.level_rect.top = self.score_rect.bottom + 10
def prep_ships(self):
'''显示还剩余多少飞船'''
self.ships = Group()
#循环剩下的飞船数,并根据数量生成位置
for ship_numbers in range(self.stats.ships_left):
ship = Ship(self.ai_settings,self.screen)
ship.rect.x = 10 + ship_numbers * (2 * ship.rect.width)
ship.rect.y = -30
self.ships.add(ship)
def show_score(self):
#在屏幕上显示得分和最高分
self.screen.blit(self.image,self.score_rect)
self.screen.blit(self.high_score_image,self.high_score_rect)
self.screen.blit(self.level_image,self.level_rect)
#绘制飞船
self.ships.draw(self.screen)
game_functions.py
#将管理事件的代码部分转移到此模块中,以简化主程序逻辑
import sys
import pygame
#导入子弹类
from bullet import Bullet
from alien import Alien
#导入json用于记录最高分
import json
#导入sleep来实现游戏暂停
from time import sleep
def fire_bullet(ai_settings,screen,ship,bullets):
# 创建一个子弹,并将其加入到编组中去
# 设置条件,限制子弹数量
#当符合条件时,按下空格发射子弹
if len(bullets) < ai_settings.bullets_allowed:
new_bullet = Bullet(ai_settings, screen, ship)
bullets.add(new_bullet)
def check_keydown_events(event,ai_settings,screen,ship,bullets,stats,aliens,sb):
#响应按键
if event.key == pygame.K_RIGHT:
# 当按键事件为按下右箭头时,向右移动标志为正确
ship.moving_right = True
elif event.key == pygame.K_LEFT:
# 当按键事件为按下左箭头时,向左移动标志为正确
ship.moving_left = True
#当按下的键为z时
elif event.key == pygame.K_z:
#简化keydown,当按下空格时调用函数fire_bullets检查条件发射子弹
fire_bullet(ai_settings,screen,ship,bullets)
#设置快捷键q用于退出游戏
elif event.key == pygame.K_q:
sys.exit()
#设置快捷键p用于重置游戏
elif event.key == pygame.K_p:
start_game(stats,aliens,bullets,ai_settings,screen,ship,sb)
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_events(ai_settinngs,ship,screen,bullets,stats,play_button,aliens,sb):
'''响应按键和鼠标事件'''
for event in pygame.event.get():
'''当事件类型为QUIT时,退出游戏'''
if event.type == pygame.QUIT:
sys.exit()
#检测鼠标事件
elif event.type == pygame.MOUSEBUTTONDOWN:
#将鼠标点击区域坐标储存到变量中
mouse_x,mouse_y = pygame.mouse.get_pos()
check_play_button(stats,play_button,mouse_x,mouse_y,aliens,bullets,ai_settinngs,screen,ship,sb)
#更新后的check_event直接使用前面定义的函数
elif event.type == pygame.KEYDOWN:
#调用时增加形参
check_keydown_events(event,ai_settinngs,screen,ship,bullets,stats,aliens,sb)
elif event.type == pygame.KEYUP:
check_keyup_events(event,ship)
'''在 KEYDOWN 和 KEYUP 中使用 if-elif 结构处理两种按键标志,因为每个事件只与一个键关联,
当同时按下左右两键时,即视为两个事件来处理'''
def check_play_button(stats,play_button,mouse_x,mouse_y,aliens,bullets,ai_settings,screen,ship,sb):
'''在玩家单击play按钮时开始新游戏'''
#将按钮点击检测储存到变量中
button_clicked = play_button.rect.collidepoint(mouse_x,mouse_y)
#当按钮被点击且游戏非运行状态时,按钮点击生效
if button_clicked:
#调用重置游戏方法
start_game(stats,aliens,bullets,ai_settings,screen,ship,sb)
def start_game(stats,aliens,bullets,ai_settings,screen,ship,sb):
'''创建重置游戏的方法'''
if not stats.game_active :
# 隐藏光标
# 向set_visible()传递参数False来隐藏光标
pygame.mouse.set_visible(False)
#重置速度
ai_settings.initialize_dynamic_settings()
# 重置统计信息
stats.reset_stats()
# 游戏运行标志正确
stats.game_active = True
#重置记分牌中的图像
sb.prep_images()
# 清空子弹和外星人
aliens.empty()
bullets.empty()
# 创建新外星人群
create_fleet(ai_settings, screen, ship, aliens)
# 飞船居中
ship.center_ship()
def update_bullets(bullets,aliens,ai_settings,screen,ship,stats,sb):
# 对编组中的每一个子弹调用update
#更新子弹位置
bullets.update()
# 删除已消失的子弹
# 在for循环中不应从列表或编组删除条目,所以使用方法copy()遍历编组的副本,然后修改编组
# 遍历副本的原因:由于编组内的子弹是动态变化的,遍历副本后根据副本元素来删除编组中对应的元素,做到精准删除
# 注意:这里删除的是原编组里的子弹!
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
#调用检测外星人子弹碰撞函数
check_bullet_alien_collisions(bullets,aliens,ai_settings,screen,ship,stats,sb)
def check_bullet_alien_collisions(bullets,aliens,ai_settings,screen,ship,stats,sb):
#检查是否有子弹击中了外星人
#如果子弹击中外星人,则删除该子弹和外星人
collisions = pygame.sprite.groupcollide(bullets,aliens,True,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(bullets,ai_settings,stats,sb,screen,ship,aliens)
def start_new_level(bullets,ai_settings,stats,sb,screen,ship,aliens):
# 清空子弹
bullets.empty()
# 提升外星人群速度
ai_settings.increase_speed()
# 提升等级
stats.level += 1
sb.prep_level()
# 创建外星人
create_fleet(ai_settings, screen, ship, aliens)
def check_high_score(stats,sb):
'''检测是否诞生了新的最高分'''
#读取json中的最高分,将最高分储存在变量,将当前分数与最高分比较
#当当前分数高于最高分时,将当前最高分储存到新变量,并将新变量写入json文件
#调用更新最高分函数,显示新的最高分
with open('high_score.json') as f_obj:
high_score = json.load(f_obj)
if stats.score > high_score :
new_high_score = stats.score
with open('high_score.json','w') as f_obj :
json.dump(new_high_score,f_obj)
sb.prep_high_score()
def get_number_aliens_x(ai_settings,alien_width):
'''整理函数,增加条理性'''
'''此函数返回每行可容下的外星人数量'''
# 按照公式来计算行的有效屏幕空间,需要与边界保持间距,间距为一个外星人矩形的宽,故行有效屏幕空间为屏宽减去两个外星人宽
# 求一行容纳外星人数量:两个外星人之间需要保留一个外星人宽的间距,即一个外星人需要的宽为两倍外星人矩形宽
# 那么行容纳外星人数量 = 行有效屏幕空间/两倍外星人矩形宽
available_space_x = ai_settings.screen_width - 2 * alien_width # 行外星人可用屏幕容量
number_aliens_x = int(available_space_x / (2 * alien_width)) # 行容纳外星人数量
'''这里使用了int来求得整数数量的外星人,舍弃了小部分,防止出现不完整外星人,同时也出于生成的目的,
函数range()需要一个整数值'''
return number_aliens_x
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
def create_alien(ai_settings, screen, aliens, alien_number, row_number):
'''创建单个外星人并将其放在行中'''
# 先创建单个外星人
# 外星人间距为外星人宽度
alien = Alien(ai_settings, screen)
alien_width = alien.rect.width
# 外星人位置从左算起,空掉一个外星人矩形作为间隔,每个外星人占据两个外星人矩形大小,
# x 轴排布位置由for循环的外星人次序决定,故 * number_aliens_x
alien.x = alien_width + 2 * alien_width * alien_number
# 储存外星人坐标
alien.rect.x = alien.x
# 外星人行的位置需空出一行作为与顶的边界,同时行与行之间空出一个外星人高度作为间距
# y 轴排布位置由for循环的行数次序决定,故 * row_number
alien.rect.y = 30 + alien.rect.height + 2 * alien.rect.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, 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)
#增加了子弹和外星人形参
def update_screen(ai_settings,ship,screen,aliens,bullets,stats,play_button,sb):
'''设置、飞船、屏幕为三个实参,在方法中使用'''
#屏幕颜色填充为设置中设置的颜色
screen.fill(ai_settings.bg_color)
#在飞船和外星人后面重绘所有子弹
#在背景设置完毕后将飞船绘制到指定位置
ship.blitme()
#绘制外星人编组中的每一个
aliens.draw(screen)
'''遍历编组中的每一个精灵(子弹),并对每一个精灵(子弹)调用draw_bullte'''
# 这里使用了方法bullets.sprites 它返回子弹编组 注意sprites是复数
for bullet in bullets.sprites():
bullet.draw_bullet()
#显示得分
sb.show_score()
#让最近绘制的屏幕可见
#当游戏处于非活动状态,绘制按钮
if not stats.game_active :
play_button.draw_button()
#让最近绘制的屏幕可见
pygame.display.flip()
def check_fleet_edges(ai_settings,aliens):
#遍历每一个外星人,当触碰边缘时调用改变方向函数
for alien in aliens.sprites():
if alien.check_edges():
change_fleet_direction(ai_settings,aliens)
'''由于之前这里忘记break退出循环,外星人群有时会直接下落导致游戏结束'''
break
def change_fleet_direction(ai_settings,aliens):
#遍历每一个外星人,调整每一个外星人的 y 坐标,即下降
for alien in aliens.sprites():
alien.rect.y += ai_settings.alien_drop_factor
#改变方向值
ai_settings.fleet_direction *= -1
def check_alien_bottom(ai_settings,ship,aliens,stats,bullets,screen,sb):
#检查外星人是否触底
#注意!!!
#get_rect()要记得加上括号,不然会出现如下错误:
# AttributeError: 'builtin_function_or_method' object has no attribute 'bottom'
screen_rect = screen.get_rect()
#遍历外星人编组
for alien in aliens.sprites():
#当有外星人触底时,调用ship_hit函数更新外星人和飞船
if alien.rect.bottom >= screen_rect.bottom:
ship_hit(stats,aliens,bullets,ai_settings,screen,ship,sb)
break
def update_aliens(ai_settings,ship,aliens,stats,bullets,screen,sb):
'''检查外星人是否触碰边缘,做出调整'''
check_fleet_edges(ai_settings,aliens)
# 对每个外星人的位置更新
aliens.update()
#检查外星人与飞船的碰撞,当碰撞时发出信号(已删去)
#在碰撞时调用ship_hit,做出相应变化
if pygame.sprite.spritecollideany(ship,aliens):
ship_hit(stats,aliens,bullets,ai_settings,screen,ship,sb)
#调用函数检查是否有外星人触底
check_alien_bottom(ai_settings,ship,aliens,stats,bullets,screen,sb)
def ship_hit(stats,aliens,bullets,ai_settings,screen,ship,sb):
#检查飞船数量是否用完,若未用完,暂停后更新飞船和外星人;若用完,标志False,没有更新,游戏结束
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
#暂停0.5秒
sleep(0.5)
elif stats.ships_left == 0:
#当飞船数量用完,标志错误,不执行更新
stats.game_active = False
#在游戏处于非运行状态时,光标出现,可以点击按钮继续游戏
pygame.mouse.set_visible(True)
alien_invasion.py
#游戏主程序
#模块sys可用于退出游戏,因为模块game_functions中已经导入sys,主程序中不需要再导入
import pygame
from settings import Settings
from ship import Ship
#导入信息统计类
from game_stats import GameStats
from scoreboard import Scoreboard
#导入编组
from pygame.sprite import Group
#由于不在主程序创建外星人实例,此处不必导入
#导入game_functions,后面的事件管理部分从模块导入
import game_functions as gf
#导入按钮类
from button import Button
def run_game():
#初始化游戏并创建一个屏幕
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
#设置屏幕对象
pygame.display.set_caption("alien_invision")
#创建按钮类 形参msg对应的实参为“play”
play_button = Button(ai_settings,screen,"Play")
#创建一个用于储存游戏信息统计的实例
stats = GameStats(ai_settings)
#创建记分牌实例
sb = Scoreboard(screen,ai_settings,stats)
#创建一艘飞船
ship = Ship(ai_settings,screen)
#创建一个子弹编组
bullets = Group()
#创建一个外星人编组
aliens = Group()
# 使用gf模块中的函数绘制外星人群
gf.create_fleet(ai_settings,screen,ship,aliens)
#开始游戏主循环
while True:
#使用模块game_funcations中的方法
#check_events检测按键和鼠标点击事件
gf.check_events(ai_settings,ship,screen,bullets,stats,play_button,aliens,sb)
#当标志正确时运行游戏:
if stats.game_active :
#方法update()用于确定事件标志以及移动距离和方向
ship.update()
#使用更新后的gf的函数用于更新和删除子弹
#检测外星人与子弹的碰撞,删除外星人与子弹 并创建外星人群
gf.update_bullets(bullets,aliens,ai_settings,screen,ship,stats,sb )
#由于外星人会被子弹击中,所以在绘制子弹之后绘制外星人
gf.update_aliens(ai_settings,ship,aliens,stats,bullets,screen,sb)
#方法update_screen用于更新绘制屏幕各元素
gf.update_screen(ai_settings,ship,screen,aliens,bullets,stats,play_button,sb)
#运行游戏
run_game()