武装飞船
开辟一个名为《外星人入侵》的游戏吧!为此将使用 Pygame,这是一组功能强盛而风趣的模块,可用于管理图形、动画以致声音, 让你可以大概更轻松地开辟复杂的游戏。通过使用Pygame来处置处罚在屏幕上绘制图像 等任务,可将重点放在步调的高级逻辑上。
你将安装Pygame,再创建一艘可以大概根据用户输入左右移动和射击的飞船。在接下来的两章,你将创建一群作为射杀目标的外星人,并改进该游戏:限定可供玩家使用的飞船数,而且添加记分牌。
玩家控制一艘最初出现在屏幕底部中央的飞船。玩 家可以使用箭头键左右移动飞船,还可使用空格键射击。游戏开始时,一群外 星人出现在天空中,并向屏幕下方移动。玩家的任务是射杀这些外星人。玩家 将全部外星人都清除干净后,将出现一群新的外星人,其移动速率更快。只要 有外星人撞到玩家的飞船或到达屏幕底部,玩家就丧失一艘飞船。玩家丧失三艘飞船后,游戏竣事。
一.第三阶段
本章将竣事游戏《外星人入侵》的开辟。我们会添加一个Play 按钮,用于根据须要启动游戏以及在游戏竣事后重启游戏,还会修改这个游 戏,使其随玩家品级进步而加快节奏,并实现一个记分体系。阅读本章后,你 将把握充足多的知识,可以大概开始编写随玩家品级进步而加浩劫度以及体现得分的游戏。
1.1添加Play按钮
添加一个Play按钮,它在游戏开始前出现,并在游戏竣事后再次出现,让玩家可以大概开始新游戏。- def __init__(self, ai_game):
- """初始化统计信息。"""
- self.settings = ai_game.settings
- self.reset_stats()
-
- # 让游戏一开始处于非活动状态。
- self.game_active = False
复制代码 1.1.1创建 Button 类
由于Pygame没有内置创建按钮的方法,编写一个Button 类,用于创建带标 签的实心矩形。- import pygame.font
- class Button:
- def __init__(self,ai_game,msg): #1
- """初始化按钮的属性。"""
- self.screen=ai_game.screen
- self.screen_rect=self.screen.get_rect()
- # 设置按钮的尺寸和其他属性。
- self.width,self.height=200,50 #2
- self.button_color=(0,255,0)
- self.text_color=(255,255,255)
- self.font=pygame.font.SysFont(None,48) #3
-
- # 创建按钮的rect对象,并使其居中。
- self.rect=pygame.Rect(0,0,self.width,self.height)
- self.rect.center=self.screen_rect.center
-
- # 按钮的标签只创建一次。
- self._prep_msg(msg) #4
-
复制代码 导入模块pygame.font ,让Pygame可以大概将文本渲染到屏幕上。方法 __init__() 继承参数self 、对象ai_game 和msg ,此中msg是要在按钮中体现的文本(#1)。设置按钮的尺寸(#2),再通过设置button_color ,让按钮的rect 对象为亮绿色,并通过设置text_color 让文本为白色。
在(#3)处,指定使用什么字体来渲染文本。实参None 让Pygame使用默认字体,而48 指定了文本的字号。为让按钮在屏幕上居中,创建一个体现按钮的rect 对象(#4),并将其center 属性设置为屏幕的center 属性。
Pygame处置处罚文本的方式是,将要体现的字符串渲染为图像。在(#5)处,调用了 _prep_msg() 来处置处罚如许的渲染。
button.py- def _prep_msg(self,msg):
- """将msg渲染为图像,并使其在按钮上居中。"""
- self.msg_image=self.font.render(msg,True,self.text_color, #1
- self.button_color)
- self.msg_image_rect=self.msg_image.get_rect() #2
- self.msg_image_rect.center=self.rect.center
复制代码 方法_prep_msg() 继承实参self 以及要渲染为图像的文本(msg )。调用 font.render() 将存储在msg 中的文本转换为图像,再将该图像存储在 self.msg_image 中(#1)。方法font.render() 还继承一个布尔实参,该 实参指定开启照旧关闭反锯齿功能(反锯齿让文本的边沿更平滑)。余下的两个实 参分别是文本颜色和配景致。我们启用了反锯齿功能,并将文本的配景致设置为按 钮的颜色。(如果没有指定配景致,Pygame渲染文本时将使用透明配景。)
在(#2)处,让文本图像在按钮上居中:根据文本图像创建一个rect ,并将其center 属性设置为按钮的center 属性。 末了,创建方法draw_button() ,用于将这个按钮体现到屏幕上:
创建方法draw_button() ,用于将这个按钮体现到屏幕上:
button.py- def draw_button(self):
- # 绘制一个用颜色填充的按钮,再绘制文本。
- self.screen.fill(self.button_color, self.rect)
- self.screen.blit(self.msg_image, self.msg_image_rect)
复制代码 调用screen.fill() 来绘制体现按钮的矩形,再调用screen.blit() 并向 它转达一幅图像以及与该图像干系联的rect ,从而在屏幕上绘制文本图像。
1.1.2在屏幕上绘制按钮
更新 import 语句:
alien_invasion.py- --snip--
- from game_stats import GameStats
- from button import Button
复制代码 alien_invasion.py- def __init__(self):
- --snip--
- self._create_fleet()
- #创建Play按钮。
- self.play_button = Button(self, "Play")
复制代码 alien_invasion.py- def _update_screen(self):
- --snip--
- self.aliens.draw(self.screen)
- # 如果游戏处于非活动状态,就绘制Play按钮。
- if not self.stats.game_active:
- self.play_button.draw_button()
- pygame.display.flip()
复制代码 为让Play按钮位于其他全部屏幕元素上面,在绘制其他全部游戏元素后再绘制这个 按钮,然后切换到新屏幕。将这些代码放在一个if 代码块中,让按钮仅在游戏出于 非运动状态时才出现。
1.1.3开始游戏
为在玩家单击Play按钮时开始新游戏,在_check_events() 末端添加如下elif 代码块,以监视与该按钮干系的鼠标变乱:
alien_invasion.py- def _check_events(self):
- """响应按键和鼠标事件。"""
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- --snip--
- elif event.type == pygame.MOUSEBUTTONDOWN: #1
- mouse_pos = pygame.mouse.get_pos() #2
- self._check_play_button(mouse_pos) #3
复制代码 无论玩家单击屏幕的什么地方,Pygame都将检测到一个MOUSEBUTTONDOWN 变乱 (#1),但我们只想让这个游戏在玩家用鼠标单击Play按钮时做出相应。为此,使 用了pygame.mouse.get_pos() ,它返回一个元组,此中包罗玩家单击时鼠标的 坐标和 坐标(#2)。我们将这些值转达给新方法_check_play_button() (#3)
alien_invasion.py- def _check_play_button(self, mouse_pos):
- """在玩家单击Play按钮时开始新游戏。"""
- if self.play_button.rect.collidepoint(mouse_pos):
- self.stats.game_active = True
复制代码 使用了rect 的方法collidepoint() 查抄鼠标单击位置是否在Play按钮的 rect 内。如果是,就将game_active 设置为True ,让游戏开始!
1.1.4重置游戏
为在玩家每次单击Play按钮时都重置游戏,须要重置统计信息、删除现有的外星人 和子弹、创建一群新的外星人并让飞船居中
alien_invasion.py- def _check_play_button(self,mouse_pos):
- """在玩家单击Play按钮时开始新游戏。"""
- if self.play_button.rect.collidepoint(mouse_pos):
- #重置游戏统计信息。
- self.stats.reset_stats()
- self.stats.game_active= True
- #清空余下的外星人和子弹。
- self.aliens.empty()
- self.bullets.empty()
-
- #创建一群新的外星人并让飞船居中。
- self._create_fleet()
- self.ship.center_ship()
复制代码 重置游戏统计信息,给玩家提供三艘新飞船。接下来,将game_active 设置为True 。如许,这个方法的代码实行完毕后,游戏就将开始。清空编组 aliens 和bullets ,然后创建一群新的外星人并将飞船居中。
1.1.5将Play按钮切换到非运动状态、
存在一个标题:即便Play按钮不可见,玩家单击其地点的地域时,游戏依然会 做出相应。游戏开始后,如果玩家不警惕单击了Play按钮所处的地域,游戏将重新 开始! 为修复这个标题,可让游戏仅在game_active 为False 时才开始:
alien_invasion.py- def _check_play_button(self, mouse_pos):
- """玩家单击Play按钮时开始新游戏。"""
- button_clicked = self.play_button.rect.collidepoint(mouse_pos) #1
- if button_clicked and not self.stats.game_active: #2
- #重置游戏统计信息。
- self.stats.
复制代码 标记button_clicked 的值为True 或False (#1)。仅当玩家单击了Play按 钮 且 游戏当前处于非运动状态时,游戏才重新开始(#2)。
1.1.6潜伏鼠标光标
alien_invasion.py- def _check_play_button(self, mouse_pos):
- """在玩家单击Play按钮时开始新游戏。"""
- button_clicked = self.play_button.rect.collidepoint(mouse_pos)
- if button_clicked and not self.stats.game_active:
- --snip--
- #隐藏鼠标光标。
- pygame.mouse.set_visible(False)
复制代码 通过向set_visible() 转达False ,让Pygame在光标位于游戏窗口内时将其潜伏 起来。 游戏竣事后,将重新体现光标,让玩家可以大概单击Play按钮来开始新游戏。
alien_invasion.py- def _ship_hit(self):
- """响应飞船被外星人撞到。"""
- if self.stats.ships_left > 0:
- --snip--
- else:
- self.stats.game_active = False
- pygame.mouse.set_visible(True)
复制代码 1.2进步品级
当前,将整群外星人清除干净后,玩家将进步一个品级,但游戏的难度没变。下面 来增长一点意见意义性:每当玩家将屏幕上的外星人清除干净后,都加快游戏的节奏, 让游戏玩起来更难。
1.2.1修改速率设置
起首重新构造Settings 类,将游戏设置分别成静态和动态两组。对于随着游戏进 行而厘革的设置,还要确保在开始新游戏时举行重置。settings.py的方法 __init__() 如下:
settings.py- def __init__(self):
- """初始化游戏的静态设置。"""
- #屏幕设置
- self.screen_width = 1200
- self.screen_height = 800
- self.bg_color = (230, 230, 230)
- #飞船设置
- self.ship_limit = 3
-
- #子弹设置
- self.bullet_width = 3
- self.bullet_height = 15
- self.bullet_color = 60, 60, 60
- self.bullets_allowed = 3
- #外星人设置
- self.fleet_drop_speed = 10
- # 加快游戏节奏的速度。
- self.speedup_scale = 1.1 #1
- self.initialize_dynamic_settings() #2
复制代码 在(#1)处,添加设置speedup_scale ,用 于控制游戏节奏的加快速率:2体现玩家每进步一个品级,游戏的节奏就翻一倍;1 体现游戏节奏始终稳固。将其设置为1.1可以大概将游戏节奏进步到充足快,让游戏既有 难度又并非不可完成。末了,调用initialize_dynamic_settings() 初始化 随游戏举行而厘革的属性(#2)。
settings.py- def initialize_dynamic_settings(self):
- """初始化随游戏进行而变化的设置。"""
- self.ship_speed = 1.5
- self.bullet_speed = 3.0
- self.alien_speed = 1.0
- # fleet_direction为1表示向右,为-1表示向左。
- self.fleet_direction = 1
复制代码 这个方法设置飞船、子弹和外星人的初始速率。随着游戏的举行,将进步这些速 度。每当玩家开始新游戏时,都将重置这些速率。在这个方法中,还设置了 fleet_direction ,使得游戏刚开始时,外星人总是向右移动。不须要增大 fleet_drop_speed 的值,由于外星人移动的速率越快,到达屏幕底端所需的时 间越短。
为在玩家的品级进步时进步飞船、子弹和外星人的速率,编写一个名为 increase_speed() 的新方法:settings.py- def increase_speed(self):
- """提高速度设置"""
- self.ship_speed *= self.speedup_scale
- self.bullet_speed *= self.speedup_scale
- self.alien_speed *= self.speedup_scale
复制代码 在_check_bullet_alien_collisions() 中,在整群外星人都被清除后调用 increase_speed() 来加快游戏的节奏
alien_invasion.py- def _check_bullet_alien_collisions(self):
- --snip--
- if not self.aliens:
- # 删除现有的子弹并创建一群新的外星人。
- self.bullets.empty()
- self._create_fleet()
- self.settings.increase_speed()
复制代码 1.2.2重置速率
每当玩家开始新游戏时,都须要将发生了厘革的设置重置为初始值,否则新游戏开 始时,速率设置将为前一次进步后的值:
alien_invasion.py- def _check_play_button(self, mouse_pos):
- """在玩家单击Play按钮时开始新游戏。"""
- button_clicked = self.play_button.rect.collidepoint(mouse_pos)
- if button_clicked and not self.stats.game_active:
- #重置游戏设置。
- self.settings.initialize_dynamic_settings()
- --snip--
复制代码 1.3记分
实现一个记分体系,以实时跟踪玩家的得分,并体现最高得分、品级和余下的飞船数。
得分是游戏的一项统计信息,因此在GameStats 中添加一个score 属性:
game_stats.py- class GameStats:
- --snip--
- def reset_stats(self):
- """初始化随游戏进行可能变化的统计信息。"""
- self.ships_left = self.ai_settings.ship_limit
- self.score = 0
复制代码 为在每次开始游戏时都重置得分,我们在reset_stats() 而不是__init__() 中 初始化score 。
1.3.1体现得分
为在屏幕上体现得分,起首创建一个新类Scoreboard 。
scoreboard.py- import pygame.font
- class Scoreboard:
- """显示得分信息的类。"""
- def __init__(self,ai_game): #1
- """初始化得分涉及的属性。"""
- self.screen=ai_game.screen
- self.screen.rect=ai_game.screen.get_rect()
- self.settings=ai_game.settings
- self.stats=ai_game.stats
- # 显示得分信息时使用的字体设置。
- self.text_color=(30,30,30) #2
- self.font=pygame.font.SysFont(None,48) #3
- # 准备初始得分图像。
- self.prep_score() #4
复制代码 由于Scoreboard 在屏幕上体现文本,起首导入模块pygame.font 。接下来,在 __init__() 中包罗形参ai_game ,以便访问陈诉跟踪的值所需的对象 settings 、screen 和stats (#1)。然后,设置文本颜色(#2)并实例化 一个字体对象(#3)。 为将要体现的文本转换为图像,调用prep_score() (#4),其界说如下:
scoreboard.py- def prep_score(self):
- """将得分转换为渲染的图像。"""
- score_str=str(self.stats.score) #1
- self.score_image=self.font.render(score_str,True,
- self.text_color,self.settings.bg_color)#2
- # 将得分放在屏幕右上角。
- self.score_rect=self.score_image.get_rect() #3
- self.score_rect.right=self.screen_rect.right-20 #4
- self.score_rect.top=20 #5
-
复制代码 在prep_score() 中,将数值stats.score 转换为字符串(#1),再将这个字 符串转达给创建图像的render() (#2)。为在屏幕上清晰地体现得分,向 render() 转达屏幕配景致和文本颜色。 将得分放在屏幕右上角,并在得分增大导致数变宽时让其向左延伸。为确保得分始 终锚定在屏幕右边,创建一个名为score_rect 的rect (#3),让其右边沿与 屏幕右边沿相距20像素(#4),并让其上边沿与屏幕上边沿也相距20像素(#5)。 接下来,创建方法show_score() ,用于体现渲染好的得分图像:
scoreboard.py- def show_score(self):
- """在屏幕上显示得分。"""
- self.screen.blit(self.score_image, self.score_rect)
复制代码 1.3.2创建记分牌
为体现得分,在AlienInvasion 中创建一个Scoreboard 实例。先来更新 import 语句:
alien_invasion.py- --snip--
- from game_stats import GameStats
- from scoreboard import Scoreboard
- --snip--
复制代码 接下来,在方法__init__() 中创建一个Scoreboard 实例:
alien_invasion.py- def __init__(self):
- --snip--
- pygame.display.set_caption("Alien Invasion")
-
- #创建存储游戏统计信息的实例,
- #并创建记分牌。
- self.stats = GameStats(self)
- self.sb = Scoreboard(self)
- --snip--
复制代码 然后,在_update_screen() 中将记分牌绘制到屏幕上:- def _update_screen(self):
- --snip--
- self.aliens.draw(self.screen)
- #显示得分。
- self.sb.show_score()
- #如果游戏处于非活动状态,就显示Play按钮。
- --snip--
复制代码 alien_invasion.py- def _update_screen(self):
- --snip--
- self.aliens.draw(self.screen)
- #显示得分。
- self.sb.show_score()
- # 如果游戏处于非活动状态,就显示Play按钮。
- --snip--
复制代码 在体现Play按钮前调用show_score() 。
1.3.3 在外星人被清除时更新得分
为在屏幕上实时体现得分,每当有外星人被击中时,都更新stats.score 的值, 再调用prep_score() 更新得分图像。但在此之前,须要指定玩家每击落一个外星 人将得到多少分:
settings.py- def initialize_dynamic_settings(self):
- --snip--
- # 记分
- self.alien_points = 50
复制代码 随着游戏的举行,将进步每个外星人的分数。为确保每次开始新游戏时这个值都会 被重置,我们在initialize_dynamic_settings() 中设置它。
在_check_bullet_alien_collisions() 中,每当有外星人被击落时,都更新得分:
alien_invasion.py- def _check_bullet_alien_collisions(self):
- """响应子弹和外星人发生碰撞。"""
- #删除彼此碰撞的子弹和外星人。
-
- collisions = pygame.sprite.groupcollide(
- self.bullets, self.aliens, True, True)
- if collisions:
- self.stats.score += self.settings.alien_points
- self.sb.prep_score()
- --snip--
复制代码 有子弹击中外星人时,Pygame返回一个字典(collisions )。我们查抄这个字典 是否存在,如果存在,就将得分加上一个外星人的分数。接下来,调用 prep_score() 来创建一幅包罗最新得分的新图像。
1.3.4重置得分
当前,仅在有外星人被射杀 之后 天生得分。这在大多数环境下可行,但从开始新游 戏到有外星人被射杀之间,体现的是上一次的得分。 为修复这个标题,可在开始新游戏时天生得分:
alien_invasion.py- def _check_play_button(self, mouse_pos):
- --snip--
- if button_clicked and not self.stats.game_active:
- --snip--
- # 重置游戏统计信息。
- self.stats.reset_stats()
- self.stats.game_active = True
- self.sb.prep_score()
- --snip--
复制代码 开始新游戏时,我们重置游戏统计信息再调用prep_score() 。此时天生的记分牌 上体现的得分为零。
1.3.5将清除的每个外星人都计入得分
当前的代码大概会遗漏一些被清除的外星人。比方,如果在一次循环中,有两颗子 弹击中了外星人,大概因子弹较宽而同时击中了多个外星人,玩家将只能得到一个 外星人的分数。为修复这种标题,我们来调解检测子弹和外星人碰撞的方式。
在_check_bullet_alien_collisions() 中,与外星人碰撞的子弹都是字典 collisions 中的一个键,而与每颗子弹干系的值都是一个列表,此中包罗该子弹 击中的外星人。我们遍历字典collisions ,确保将清除的每个外星人都计入得分:
alien_invasion.py- def _check_bullet_alien_collisions(self):
- --snip--
- if collisions:
- for aliens in collisions.values():
- self.stats.score += self.settings.alien_points * len(aliens)
- self.sb.prep_score()
复制代码 如果字典collisions 存在,就遍历此中的全部值。别忘了,每个值都是一个列 表,包罗被同一颗子弹击中的全部外星人。对于每个列表,都将其包罗的外星人数 量乘以一个外星人的分数,并将效果到场当前得分。
1.3.6进步分数
鉴于玩家每进步一个品级,游戏都变得更难,因此处于较高的品级时,外星人的分 数应更高。
settings.py- class Settings:
- """存储游戏《外星人入侵》的所有设置的类。"""
-
- def __init__(self):
- --snip--
- # 加快游戏节奏的速度。
- self.speedup_scale = 1.1
- # 外星人分数的提高速度。
- self.score_scale = 1.5 #1
-
- self.initialize_dynamic_settings()
-
- def initialize_dynamic_settings(self):
- --snip--
-
- def increase_speed(self):
- """提高速度设置和外星人分数。"""
- self.ship_speed *= self.speedup_scale
- self.bullet_speed *= self.speedup_scale
- self.alien_speed *= self.speedup_scale
-
- self.alien_points = int(self.alien_points * self.score_scale) #2
复制代码 界说了分数的进步速率,并称之为score_scale (#1)。较低的节奏加快 速率(1.1)让游戏很快变得极具挑衅性,但为了让记分发生明显的厘革,须要将分 数的进步速率设置为更大的值(1.5)。现在,在加快游戏节奏的同时,进步了每个 外星人的分数(#2)。为让分数为整数,使用了函数int() 。
1.3.7舍入得分
将得分体现为10的整数倍,下面让记分体系遵照这个原 则。我们还将设置得分的格式,在大数中添加用逗号体现的千位分隔符。在 Scoreboard 中实行这种修改:
scoreboard.py- def prep_score(self):
- """将得分转换为渲染的图像。"""
- rounded_score = round(self.stats.score, -1) #1
- score_str = "{:,}".format(rounded_score) #2
- self.score_image = self.font.render(score_str, True,
- self.text_color, self.settings.bg_color)
- --snip--
复制代码 函数round() 通常让小数正确到小数点后某一位,此中小数位数是由第二个实参指 定的。然而,如果将第二个实参指定为负数,round() 将舍入到迩来的10的整数 倍,如10、100、1000等。(#1)处的代码让Python将stats.score 的值舍入到迩来的 10的整数倍,并将效果存储到rounded_score 中。
1.3.8最高得分
每个玩家都想高出游戏的最高得分纪录。下面来跟踪并体现最高得分,给玩家提供 要逾越的目标。我们将最高得分存储在GameStats 中:\
game_stats.py- def __init__(self, ai_game):
- --snip--
- # 任何情况下都不应重置最高得分。
- self.high_score = 0
复制代码 scoreboard.py- def __init__(self, ai_game):
- --snip--
- # 准备包含最高得分和当前得分的图像。
- self.prep_score()
- self.prep_high_score()
复制代码 最高得分将与当前得分分开体现,因此须要编写一个新方法prep_high_score() ,用于准备包罗最高得分的图像.
方法prep_high_score() 的代码如下:
scoreboard.py- def prep_high_score(self):
- """将最高得分转换为图像。"""
- high_score = round(self.stats.high_score, -1) #1
- high_score_str = "{:,}".format(high_score)
- self.high_score_image = self.font.render(high_score_str, True, #2
- self.text_color, self.settings.bg_color)
- # 将最高得分放在屏幕顶部中央。
- self.high_score_rect = self.high_score_image.get_rect()
- self.high_score_rect.centerx = self.screen_rect.centerx #3
- self.high_score_rect.top = self.score_rect.top #4
复制代码 将最高得分舍入到迩来的10的整数倍,并添加用逗号体现的千分位分隔符(#1)。 然后,根据最高得分天生一幅图像(#2),使其水平居中(#3),并将其top 属性设置为当前得分图像的top 属性(#4)
现在,方法show_score() 须要在屏幕右上角体现当前得分,并在屏幕顶部中央显 示最高得分:
scoreboard.py- def show_score(self):
- """在屏幕上显示得分。"""
- self.screen.blit(self.score_image, self.score_rect)
- self.screen.blit(self.high_score_image, self.high_score_rect)
复制代码 为查抄是否诞生了新的最高得分,在Scoreboard 中添加一个新方法 check_high_score() :
scoreboard.py- def check_high_score(self):
- """检查是否诞生了新的最高得分。"""
- if self.stats.score > self.stats.high_score:
- self.stats.high_score = self.stats.score
- self.prep_high_score()
复制代码 方法check_high_score() 比力当前得分和最高得分。如果当前得分更高,就更 新high_score 的值,并调用prep_high_score() 来更新包罗最高得分的图像。
在_check_bullet_alien_collisions() 中,每当有外星人被清除时,都须要 在更新得分后调用check_high_score() :
alien_invasion.py- def _check_bullet_alien_collisions(self):
- --snip--
- if collisions:
- for aliens in collisions.values():
- self.stats.score += self.settings.alien_points * len(aliens)
- self.sb.prep_score()
- self.sb.check_high_score()
- --snip--
复制代码 如果字典collisions 存在,就根据清除了多少外星人更新得分,再调用 check_high_score() 。
1.3.9体现品级
为在游戏中体现玩家的品级,起首须要在GameStats 中添加一个体现当前品级的 属性。为确保每次开始新游戏时都重置品级,在reset_stats() 中初始化它:
game_stats.py- def reset_stats(self):
- """初始化随游戏进行可能变化的统计信息。"""
- self.ships_left = self.settings.ship_limit
- self.score = 0
- self.level = 1
复制代码 为了让Scoreboard 体现当前品级,在__init__() 中调用一个新方法 prep_level() :
scoreboard.py- def __init__(self, ai_game):
- --snip--
- self.prep_high_score()
- self.prep_level()
复制代码 prep_level() 的代码如下:
scoreboard.py- def prep_level(self):
- """将等级转换为渲染的图像。"""
- level_str = str(self.stats.level)
- self.level_image = self.font.render(level_str, True, #1
- self.text_color, self.settings.bg_color)
-
- # 将等级放在得分下方。
- self.level_rect = self.level_image.get_rect()
- self.level_rect.right = self.score_rect.right #2
- self.level_rect.top = self.score_rect.bottom + 10 #3
复制代码 方法prep_level() 根据存储在stats.level 中的值创建一幅图像(#1),并 将其right 属性设置为得分的right 属性(#2)。然后,将top 属性设置为比 得分图像的bottom 属性大10像素,以便在得分和品级之间留出肯定的空间(#3)。 还须要更新show_score() :
scoreboard.py- def show_score(self):
- """在屏幕上显示得分和等级。"""
- self.screen.blit(self.score_image, self.score_rect)
- self.screen.blit(self.high_score_image, self.high_score_rect)
- self.screen.blit(self.level_image, self.level_rect)
复制代码 新增的代码行在屏幕上体现品级图像。 我们在_check_bullet_alien_collisions() 中进步品级并更新品级图像:
alien_invasion.py- def _check_bullet_alien_collisions(self):
- --snip--
- if not self.aliens:
- # 删除现有的子弹并新建一群外星人。
- self.bullets.empty()
- self._create_fleet()
- self.settings.increase_speed()
- # 提高等级。
- self.stats.level += 1
- self.sb.prep_level()
复制代码 如果整群外星人都被清除,就将stats.level 的值加1,并调用prep_level() 确保正确地体现了新品级。 为确保在开始新游戏时更新品级图像,还需在玩家单击按钮Play时调用 prep_level() : alien_invasion.py- def _check_play_button(self, mouse_pos):
- --snip--
- if button_clicked and not self.stats.game_active:
- --snip--
- self.sb.prep_score()
- self.sb.prep_level()
- --snip--
复制代码 1.3.10体现余下的飞船数
起首,须要让Ship 继承Sprite ,以便创建飞船编组:
ship.py- import pygame
- from pygame.sprite import Sprite
- class Ship(Sprite): #1
- """管理飞船的类。"""
- def __init__(self, ai_game):
- """初始化飞船并设置其起始位置。"""
- super().__init__() #2
- --snip--
复制代码 这里导入了Sprite ,让Ship 继承Sprite (#1),并在__init__() 的开头 调用super() (#2)。
接下来,须要修改Scoreboard ,以创建可供体现的飞船编组。下面是此中的 import 语句: scoreboard.py- import pygame.font
- from pygame.sprite import Group
- from ship import Ship
复制代码 鉴于须要创建飞船编组,导入Group 和Ship 类。 下面是方法__init__() : scoreboard.py- def __init__(self, ai_game):
- """初始化记录得分的属性。"""
- self.ai_game = ai_game
- self.screen = ai_game.screen
- --snip--
- self.prep_level()
- self.prep_ships()
复制代码 在调用 prep_level() 后调用了prep_ships() 。 prep_ships() 的代码如下:
scoreboard.py- def prep_ships(self):
- """显示还余下多少艘飞船。"""
- self.ships = Group() #1
- for ship_number in range(self.stats.ships_left): #2
- ship = Ship(self.ai_game)
- ship.rect.x = 10 + ship_number * ship.rect.width #3
- ship.rect.y = 10 #4
- self.ships.add(ship) #5
复制代码 方法prep_ships() 创建一个空编组self.ships ,用于存储飞船实例(#1)。为添补这个编组,根据玩家尚有多少艘飞船以相应的次数运行一个循环(#2)。在这个循环中,创建新飞船并设置其 坐标,让整个飞船编组都位于屏幕左 边,且每艘飞船的左边距都为10像素(#3)。还将 坐标设置为离屏幕上边沿10像 素,让全部飞船都出现在屏幕左上角(#4)。末了,将每艘新飞船都添加到编组 ships 中(#5)。
scoreboard.py- def show_score(self):
- """在屏幕上绘制得分、等级和余下的飞船数。"""
- self.screen.blit(self.score_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)
复制代码 为在屏幕上体现飞船,对编组调用draw() 。Pygame将绘制每艘飞船。 为在游戏开始时让玩家知道自己有多少艘飞船,在开始新游戏时调用 prep_ships() 。这是在AlienInvasion 的_check_play_button() 中举行 的:
alien_invasion.py- def _check_play_button(self, mouse_pos):
- --snip--
- if button_clicked and not self.stats.game_active:
- --snip--
- self.sb.prep_score()
- self.sb.prep_level()
- self.sb.prep_ships()
- --snip--
复制代码 还要在飞船被外星人撞到时调用prep_ships() ,从而在玩家丧失飞船时更新飞船 图像: alien_invasion.py- def _ship_hit(self):
- """响应飞船被外星人撞到。"""
- if self.stats.ships_left > 0:
- #将ships_left减1并更新记分牌。
- self.stats.ships_left -= 1
- self.sb.prep_ships()
- --snip--
复制代码 这里在将ships_left 的值减1后调用prep_ships() 。如许每次丧失飞船后,显 示的飞船数都是正确的。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |