外星人入侵-Python-三

[复制链接]
发表于 2025-10-13 16:20:19 | 显示全部楼层 |阅读模式
武装飞船

开辟一个名为《外星人入侵》的游戏吧!为此将使用 Pygame,这是一组功能强盛而风趣的模块,可用于管理图形、动画以致声音, 让你可以大概更轻松地开辟复杂的游戏。通过使用Pygame来处置处罚在屏幕上绘制图像 等任务,可将重点放在步调的高级逻辑上。
你将安装Pygame,再创建一艘可以大概根据用户输入左右移动和射击的飞船。在接下来的两章,你将创建一群作为射杀目标的外星人,并改进该游戏:限定可供玩家使用的飞船数,而且添加记分牌。
玩家控制一艘最初出现在屏幕底部中央的飞船。玩 家可以使用箭头键左右移动飞船,还可使用空格键射击。游戏开始时,一群外 星人出现在天空中,并向屏幕下方移动。玩家的任务是射杀这些外星人。玩家 将全部外星人都清除干净后,将出现一群新的外星人,其移动速率更快。只要 有外星人撞到玩家的飞船或到达屏幕底部,玩家就丧失一艘飞船。玩家丧失三艘飞船后,游戏竣事。
一.第三阶段

本章将竣事游戏《外星人入侵》的开辟。我们会添加一个Play 按钮,用于根据须要启动游戏以及在游戏竣事后重启游戏,还会修改这个游 戏,使其随玩家品级进步而加快节奏,并实现一个记分体系。阅读本章后,你 将把握充足多的知识,可以大概开始编写随玩家品级进步而加浩劫度以及体现得分的游戏。
1.1添加Play按钮

添加一个Play按钮,它在游戏开始前出现,并在游戏竣事后再次出现,让玩家可以大概开始新游戏。
  1. def __init__(self, ai_game):
  2.         """初始化统计信息。"""
  3.         self.settings = ai_game.settings
  4.         self.reset_stats()
  5.         # 让游戏一开始处于非活动状态。
  6.         self.game_active = False
复制代码
1.1.1创建 Button 类

由于Pygame没有内置创建按钮的方法,编写一个Button 类,用于创建带标 签的实心矩形。
  1. import pygame.font
  2. class Button:
  3.     def __init__(self,ai_game,msg):                     #1
  4.         """初始化按钮的属性。"""
  5.         self.screen=ai_game.screen
  6.         self.screen_rect=self.screen.get_rect()
  7.         # 设置按钮的尺寸和其他属性。
  8.         self.width,self.height=200,50                   #2
  9.         self.button_color=(0,255,0)
  10.         self.text_color=(255,255,255)
  11.         self.font=pygame.font.SysFont(None,48)          #3
  12.         
  13.         # 创建按钮的rect对象,并使其居中。              
  14.         self.rect=pygame.Rect(0,0,self.width,self.height)
  15.         self.rect.center=self.screen_rect.center
  16.         
  17.         # 按钮的标签只创建一次。
  18.         self._prep_msg(msg)                              #4
  19.         
复制代码
导入模块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
  1.         def _prep_msg(self,msg):
  2.             """将msg渲染为图像,并使其在按钮上居中。"""
  3.             self.msg_image=self.font.render(msg,True,self.text_color, #1
  4.                             self.button_color)
  5.             self.msg_image_rect=self.msg_image.get_rect()             #2
  6.             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
  1. def draw_button(self):
  2.         # 绘制一个用颜色填充的按钮,再绘制文本。
  3.         self.screen.fill(self.button_color, self.rect)
  4.         self.screen.blit(self.msg_image, self.msg_image_rect)
复制代码
调用screen.fill() 来绘制体现按钮的矩形,再调用screen.blit() 并向 它转达一幅图像以及与该图像干系联的rect ,从而在屏幕上绘制文本图像。
1.1.2在屏幕上绘制按钮

更新 import 语句:
alien_invasion.py
  1. --snip--
  2. from game_stats import GameStats
  3. from button import Button
复制代码
alien_invasion.py
  1. def __init__(self):
  2.         --snip--
  3.         self._create_fleet()
  4.         #创建Play按钮。
  5.         self.play_button = Button(self, "Play")
复制代码
alien_invasion.py
  1.   def _update_screen(self):
  2.         --snip--
  3.         self.aliens.draw(self.screen)
  4.         # 如果游戏处于非活动状态,就绘制Play按钮。
  5.         if not self.stats.game_active:
  6.             self.play_button.draw_button()
  7.         pygame.display.flip()
复制代码
为让Play按钮位于其他全部屏幕元素上面,在绘制其他全部游戏元素后再绘制这个 按钮,然后切换到新屏幕。将这些代码放在一个if 代码块中,让按钮仅在游戏出于 非运动状态时才出现。

1.1.3开始游戏

为在玩家单击Play按钮时开始新游戏,在_check_events() 末端添加如下elif 代码块,以监视与该按钮干系的鼠标变乱:
alien_invasion.py
  1. def _check_events(self):
  2.           """响应按键和鼠标事件。"""
  3.           for event in pygame.event.get():
  4.               if event.type == pygame.QUIT:
  5.                   --snip--
  6.               elif event.type == pygame.MOUSEBUTTONDOWN: #1
  7.                   mouse_pos = pygame.mouse.get_pos()     #2
  8.                   self._check_play_button(mouse_pos)     #3
复制代码
无论玩家单击屏幕的什么地方,Pygame都将检测到一个MOUSEBUTTONDOWN 变乱 (#1),但我们只想让这个游戏在玩家用鼠标单击Play按钮时做出相应。为此,使 用了pygame.mouse.get_pos() ,它返回一个元组,此中包罗玩家单击时鼠标的 坐标和 坐标(#2)。我们将这些值转达给新方法_check_play_button() (#3)
alien_invasion.py
  1. def _check_play_button(self, mouse_pos):
  2.           """在玩家单击Play按钮时开始新游戏。"""
  3.           if self.play_button.rect.collidepoint(mouse_pos):
  4.               self.stats.game_active = True
复制代码
使用了rect 的方法collidepoint() 查抄鼠标单击位置是否在Play按钮的 rect 内。如果是,就将game_active 设置为True ,让游戏开始!
1.1.4重置游戏

为在玩家每次单击Play按钮时都重置游戏,须要重置统计信息、删除现有的外星人 和子弹、创建一群新的外星人并让飞船居中
alien_invasion.py
  1.     def _check_play_button(self,mouse_pos):
  2.         """在玩家单击Play按钮时开始新游戏。"""
  3.         if self.play_button.rect.collidepoint(mouse_pos):
  4.             #重置游戏统计信息。
  5.             self.stats.reset_stats()
  6.             self.stats.game_active= True
  7.             #清空余下的外星人和子弹。
  8.             self.aliens.empty()
  9.             self.bullets.empty()
  10.             
  11.             #创建一群新的外星人并让飞船居中。
  12.             self._create_fleet()
  13.             self.ship.center_ship()
复制代码
重置游戏统计信息,给玩家提供三艘新飞船。接下来,将game_active 设置为True 。如许,这个方法的代码实行完毕后,游戏就将开始。清空编组 aliens 和bullets ,然后创建一群新的外星人并将飞船居中。
1.1.5将Play按钮切换到非运动状态、

存在一个标题:即便Play按钮不可见,玩家单击其地点的地域时,游戏依然会 做出相应。游戏开始后,如果玩家不警惕单击了Play按钮所处的地域,游戏将重新 开始! 为修复这个标题,可让游戏仅在game_active 为False 时才开始:
alien_invasion.py
  1. def _check_play_button(self, mouse_pos):
  2.           """玩家单击Play按钮时开始新游戏。"""
  3.           button_clicked = self.play_button.rect.collidepoint(mouse_pos) #1
  4.           if button_clicked and not self.stats.game_active:              #2
  5.               #重置游戏统计信息。
  6.               self.stats.
复制代码
标记button_clicked 的值为True 或False (#1)。仅当玩家单击了Play按 钮 且 游戏当前处于非运动状态时,游戏才重新开始(#2)。

1.1.6潜伏鼠标光标

alien_invasion.py
  1. def _check_play_button(self, mouse_pos):
  2.         """在玩家单击Play按钮时开始新游戏。"""
  3.         button_clicked = self.play_button.rect.collidepoint(mouse_pos)
  4.         if button_clicked and not self.stats.game_active:
  5.             --snip--
  6.             #隐藏鼠标光标。
  7.             pygame.mouse.set_visible(False)
复制代码
通过向set_visible() 转达False ,让Pygame在光标位于游戏窗口内时将其潜伏 起来。 游戏竣事后,将重新体现光标,让玩家可以大概单击Play按钮来开始新游戏。
alien_invasion.py
  1. def _ship_hit(self):
  2.         """响应飞船被外星人撞到。"""
  3.         if self.stats.ships_left > 0:
  4.             --snip--
  5.         else:
  6.             self.stats.game_active = False
  7.             pygame.mouse.set_visible(True)
复制代码
1.2进步品级


当前,将整群外星人清除干净后,玩家将进步一个品级,但游戏的难度没变。下面 来增长一点意见意义性:每当玩家将屏幕上的外星人清除干净后,都加快游戏的节奏, 让游戏玩起来更难。
1.2.1修改速率设置

起首重新构造Settings 类,将游戏设置分别成静态和动态两组。对于随着游戏进 行而厘革的设置,还要确保在开始新游戏时举行重置。settings.py的方法 __init__() 如下: 
settings.py
  1. def __init__(self):
  2.           """初始化游戏的静态设置。"""
  3.           #屏幕设置
  4.           self.screen_width = 1200
  5.           self.screen_height = 800
  6.           self.bg_color = (230, 230, 230)
  7.           #飞船设置
  8.           self.ship_limit = 3      
  9.    
  10.           #子弹设置
  11.           self.bullet_width = 3
  12.           self.bullet_height = 15
  13.           self.bullet_color = 60, 60, 60
  14.           self.bullets_allowed = 3
  15.           #外星人设置
  16.           self.fleet_drop_speed = 10
  17.           # 加快游戏节奏的速度。
  18.           self.speedup_scale = 1.1           #1
  19.           self.initialize_dynamic_settings() #2
复制代码
在(#1)处,添加设置speedup_scale ,用 于控制游戏节奏的加快速率:2体现玩家每进步一个品级,游戏的节奏就翻一倍;1 体现游戏节奏始终稳固。将其设置为1.1可以大概将游戏节奏进步到充足快,让游戏既有 难度又并非不可完成。末了,调用initialize_dynamic_settings() 初始化 随游戏举行而厘革的属性(#2)。
settings.py
  1. def initialize_dynamic_settings(self):
  2.         """初始化随游戏进行而变化的设置。"""
  3.         self.ship_speed = 1.5
  4.         self.bullet_speed = 3.0
  5.         self.alien_speed = 1.0
  6.         # fleet_direction为1表示向右,为-1表示向左。
  7.         self.fleet_direction = 1
复制代码
这个方法设置飞船、子弹和外星人的初始速率。随着游戏的举行,将进步这些速 度。每当玩家开始新游戏时,都将重置这些速率。在这个方法中,还设置了 fleet_direction ,使得游戏刚开始时,外星人总是向右移动。不须要增大 fleet_drop_speed 的值,由于外星人移动的速率越快,到达屏幕底端所需的时 间越短。
为在玩家的品级进步时进步飞船、子弹和外星人的速率,编写一个名为 increase_speed() 的新方法:settings.py
  1. def increase_speed(self):
  2.         """提高速度设置"""
  3.         self.ship_speed *= self.speedup_scale
  4.         self.bullet_speed *= self.speedup_scale
  5.         self.alien_speed *= self.speedup_scale
复制代码
在_check_bullet_alien_collisions() 中,在整群外星人都被清除后调用 increase_speed() 来加快游戏的节奏
alien_invasion.py
  1. def _check_bullet_alien_collisions(self):
  2.         --snip--
  3.         if not self.aliens:
  4.             # 删除现有的子弹并创建一群新的外星人。
  5.             self.bullets.empty()
  6.             self._create_fleet()
  7.             self.settings.increase_speed()
复制代码
1.2.2重置速率

每当玩家开始新游戏时,都须要将发生了厘革的设置重置为初始值,否则新游戏开 始时,速率设置将为前一次进步后的值:
alien_invasion.py
  1. def _check_play_button(self, mouse_pos):
  2.         """在玩家单击Play按钮时开始新游戏。"""
  3.         button_clicked = self.play_button.rect.collidepoint(mouse_pos)
  4.         if button_clicked and not self.stats.game_active:
  5.             #重置游戏设置。
  6.             self.settings.initialize_dynamic_settings()
  7.             --snip--
复制代码
1.3记分

实现一个记分体系,以实时跟踪玩家的得分,并体现最高得分、品级和余下的飞船数。
得分是游戏的一项统计信息,因此在GameStats 中添加一个score 属性:
game_stats.py
  1. class GameStats:
  2.     --snip--
  3.     def reset_stats(self):
  4.         """初始化随游戏进行可能变化的统计信息。"""
  5.         self.ships_left = self.ai_settings.ship_limit
  6.         self.score = 0
复制代码
为在每次开始游戏时都重置得分,我们在reset_stats() 而不是__init__() 中 初始化score 。
1.3.1体现得分

为在屏幕上体现得分,起首创建一个新类Scoreboard 。
scoreboard.py
  1. import pygame.font
  2. class Scoreboard:
  3.     """显示得分信息的类。"""
  4.     def __init__(self,ai_game):                        #1
  5.         """初始化得分涉及的属性。"""         
  6.         self.screen=ai_game.screen
  7.         self.screen.rect=ai_game.screen.get_rect()
  8.         self.settings=ai_game.settings
  9.         self.stats=ai_game.stats
  10.         # 显示得分信息时使用的字体设置。
  11.         self.text_color=(30,30,30)                     #2
  12.         self.font=pygame.font.SysFont(None,48)         #3
  13.         # 准备初始得分图像。
  14.         self.prep_score()                              #4
复制代码
由于Scoreboard 在屏幕上体现文本,起首导入模块pygame.font 。接下来,在 __init__() 中包罗形参ai_game ,以便访问陈诉跟踪的值所需的对象 settings 、screen 和stats (#1)。然后,设置文本颜色(#2)并实例化 一个字体对象(#3)。 为将要体现的文本转换为图像,调用prep_score() (#4),其界说如下:
scoreboard.py
  1.     def prep_score(self):
  2.         """将得分转换为渲染的图像。"""
  3.         score_str=str(self.stats.score)                        #1
  4.         self.score_image=self.font.render(score_str,True,
  5.                         self.text_color,self.settings.bg_color)#2
  6.         # 将得分放在屏幕右上角。
  7.         self.score_rect=self.score_image.get_rect()            #3
  8.         self.score_rect.right=self.screen_rect.right-20        #4
  9.         self.score_rect.top=20                                 #5
  10.          
复制代码
在prep_score() 中,将数值stats.score 转换为字符串(#1),再将这个字 符串转达给创建图像的render() (#2)。为在屏幕上清晰地体现得分,向 render() 转达屏幕配景致和文本颜色。 将得分放在屏幕右上角,并在得分增大导致数变宽时让其向左延伸。为确保得分始 终锚定在屏幕右边,创建一个名为score_rect 的rect (#3),让其右边沿与 屏幕右边沿相距20像素(#4),并让其上边沿与屏幕上边沿也相距20像素(#5)。 接下来,创建方法show_score() ,用于体现渲染好的得分图像:
scoreboard.py
  1.     def show_score(self):
  2.          """在屏幕上显示得分。"""
  3.          self.screen.blit(self.score_image, self.score_rect)
复制代码
1.3.2创建记分牌

为体现得分,在AlienInvasion 中创建一个Scoreboard 实例。先来更新 import 语句:
alien_invasion.py
  1. --snip--
  2. from game_stats import GameStats
  3. from scoreboard import Scoreboard
  4. --snip--
复制代码
接下来,在方法__init__() 中创建一个Scoreboard 实例:
alien_invasion.py
  1. def __init__(self):
  2.         --snip--
  3.         pygame.display.set_caption("Alien Invasion")
  4.          
  5.         #创建存储游戏统计信息的实例,
  6.         #并创建记分牌。
  7.         self.stats = GameStats(self)
  8.         self.sb = Scoreboard(self)
  9.         --snip--
复制代码
然后,在_update_screen() 中将记分牌绘制到屏幕上:
  1. def _update_screen(self):
  2.         --snip--
  3.         self.aliens.draw(self.screen)
  4.         #显示得分。
  5.         self.sb.show_score()
  6.         #如果游戏处于非活动状态,就显示Play按钮。
  7.         --snip--
复制代码
alien_invasion.py
  1. def _update_screen(self):
  2.         --snip--
  3.         self.aliens.draw(self.screen)
  4.         #显示得分。
  5.         self.sb.show_score()
  6.         # 如果游戏处于非活动状态,就显示Play按钮。
  7.         --snip--
复制代码
在体现Play按钮前调用show_score() 。
1.3.3 在外星人被清除时更新得分


为在屏幕上实时体现得分,每当有外星人被击中时,都更新stats.score 的值, 再调用prep_score() 更新得分图像。但在此之前,须要指定玩家每击落一个外星 人将得到多少分:
settings.py
  1. def initialize_dynamic_settings(self):
  2.         --snip--
  3.         # 记分
  4.         self.alien_points = 50
复制代码
随着游戏的举行,将进步每个外星人的分数。为确保每次开始新游戏时这个值都会 被重置,我们在initialize_dynamic_settings() 中设置它。
在_check_bullet_alien_collisions() 中,每当有外星人被击落时,都更新得分:
alien_invasion.py
  1. def _check_bullet_alien_collisions(self):
  2.         """响应子弹和外星人发生碰撞。"""
  3.         #删除彼此碰撞的子弹和外星人。
  4.       
  5.         collisions = pygame.sprite.groupcollide(
  6.                 self.bullets, self.aliens, True, True)
  7.         if collisions:
  8.             self.stats.score += self.settings.alien_points
  9.             self.sb.prep_score()
  10.         --snip--
复制代码
有子弹击中外星人时,Pygame返回一个字典(collisions )。我们查抄这个字典 是否存在,如果存在,就将得分加上一个外星人的分数。接下来,调用 prep_score() 来创建一幅包罗最新得分的新图像。
1.3.4重置得分

当前,仅在有外星人被射杀 之后 天生得分。这在大多数环境下可行,但从开始新游 戏到有外星人被射杀之间,体现的是上一次的得分。 为修复这个标题,可在开始新游戏时天生得分:
alien_invasion.py
  1. def _check_play_button(self, mouse_pos):
  2.         --snip--
  3.         if button_clicked and not self.stats.game_active:
  4.             --snip--
  5.             # 重置游戏统计信息。
  6.             self.stats.reset_stats()
  7.             self.stats.game_active = True
  8.             self.sb.prep_score()
  9.             --snip--
复制代码
开始新游戏时,我们重置游戏统计信息再调用prep_score() 。此时天生的记分牌 上体现的得分为零。
1.3.5将清除的每个外星人都计入得分


当前的代码大概会遗漏一些被清除的外星人。比方,如果在一次循环中,有两颗子 弹击中了外星人,大概因子弹较宽而同时击中了多个外星人,玩家将只能得到一个 外星人的分数。为修复这种标题,我们来调解检测子弹和外星人碰撞的方式。
在_check_bullet_alien_collisions() 中,与外星人碰撞的子弹都是字典 collisions 中的一个键,而与每颗子弹干系的值都是一个列表,此中包罗该子弹 击中的外星人。我们遍历字典collisions ,确保将清除的每个外星人都计入得分:
alien_invasion.py
  1. def _check_bullet_alien_collisions(self):
  2.       --snip--
  3.       if collisions:
  4.           for aliens in collisions.values():
  5.               self.stats.score += self.settings.alien_points * len(aliens)
  6.           self.sb.prep_score()
复制代码
如果字典collisions 存在,就遍历此中的全部值。别忘了,每个值都是一个列 表,包罗被同一颗子弹击中的全部外星人。对于每个列表,都将其包罗的外星人数 量乘以一个外星人的分数,并将效果到场当前得分。
1.3.6进步分数

鉴于玩家每进步一个品级,游戏都变得更难,因此处于较高的品级时,外星人的分 数应更高。
settings.py
  1.   class Settings:
  2.       """存储游戏《外星人入侵》的所有设置的类。"""
  3.       def __init__(self):
  4.           --snip--
  5.           # 加快游戏节奏的速度。
  6.           self.speedup_scale = 1.1
  7.           # 外星人分数的提高速度。
  8.           self.score_scale = 1.5                                       #1
  9.           self.initialize_dynamic_settings()
  10.       def initialize_dynamic_settings(self):
  11.           --snip--
  12.       def increase_speed(self):
  13.           """提高速度设置和外星人分数。"""
  14.           self.ship_speed *= self.speedup_scale
  15.           self.bullet_speed *= self.speedup_scale
  16.           self.alien_speed *= self.speedup_scale
  17.           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
  1. def prep_score(self):
  2.          """将得分转换为渲染的图像。"""  
  3.          rounded_score = round(self.stats.score, -1)          #1
  4.          score_str = "{:,}".format(rounded_score)             #2
  5.          self.score_image = self.font.render(score_str, True,
  6.                   self.text_color, self.settings.bg_color)
  7.           --snip--
复制代码
函数round() 通常让小数正确到小数点后某一位,此中小数位数是由第二个实参指 定的。然而,如果将第二个实参指定为负数,round() 将舍入到迩来的10的整数 倍,如10、100、1000等。(#1)处的代码让Python将stats.score 的值舍入到迩来的 10的整数倍,并将效果存储到rounded_score 中。
1.3.8最高得分

每个玩家都想高出游戏的最高得分纪录。下面来跟踪并体现最高得分,给玩家提供 要逾越的目标。我们将最高得分存储在GameStats 中:\
game_stats.py
  1. def __init__(self, ai_game):
  2.         --snip--
  3.         # 任何情况下都不应重置最高得分。
  4.         self.high_score = 0
复制代码
scoreboard.py
  1. def __init__(self, ai_game):
  2.           --snip--
  3.           # 准备包含最高得分和当前得分的图像。
  4.           self.prep_score()
  5.           self.prep_high_score()
复制代码
最高得分将与当前得分分开体现,因此须要编写一个新方法prep_high_score() ,用于准备包罗最高得分的图像.
方法prep_high_score() 的代码如下:
scoreboard.py
  1.     def prep_high_score(self):
  2.         """将最高得分转换为图像。"""
  3.         high_score = round(self.stats.high_score, -1)                   #1
  4.         high_score_str = "{:,}".format(high_score)
  5.         self.high_score_image = self.font.render(high_score_str, True,  #2
  6.                                 self.text_color, self.settings.bg_color)
  7.         # 将最高得分放在屏幕顶部中央。
  8.         self.high_score_rect = self.high_score_image.get_rect()
  9.         self.high_score_rect.centerx = self.screen_rect.centerx         #3
  10.         self.high_score_rect.top = self.score_rect.top                  #4
复制代码
将最高得分舍入到迩来的10的整数倍,并添加用逗号体现的千分位分隔符(#1)。 然后,根据最高得分天生一幅图像(#2),使其水平居中(#3),并将其top 属性设置为当前得分图像的top 属性(#4)
现在,方法show_score() 须要在屏幕右上角体现当前得分,并在屏幕顶部中央显 示最高得分:
scoreboard.py
  1. def show_score(self):
  2.         """在屏幕上显示得分。"""
  3.         self.screen.blit(self.score_image, self.score_rect)
  4.         self.screen.blit(self.high_score_image, self.high_score_rect)
复制代码
为查抄是否诞生了新的最高得分,在Scoreboard 中添加一个新方法 check_high_score() :
scoreboard.py
  1. def check_high_score(self):
  2.         """检查是否诞生了新的最高得分。"""
  3.         if self.stats.score > self.stats.high_score:
  4.             self.stats.high_score = self.stats.score
  5.             self.prep_high_score()
复制代码
方法check_high_score() 比力当前得分和最高得分。如果当前得分更高,就更 新high_score 的值,并调用prep_high_score() 来更新包罗最高得分的图像。
在_check_bullet_alien_collisions() 中,每当有外星人被清除时,都须要 在更新得分后调用check_high_score() :
alien_invasion.py
  1. def _check_bullet_alien_collisions(self):
  2.         --snip--
  3.         if collisions:
  4.             for aliens in collisions.values():
  5.                 self.stats.score += self.settings.alien_points * len(aliens)
  6.             self.sb.prep_score()
  7.             self.sb.check_high_score()
  8.         --snip--
复制代码
如果字典collisions 存在,就根据清除了多少外星人更新得分,再调用 check_high_score() 。
1.3.9体现品级


为在游戏中体现玩家的品级,起首须要在GameStats 中添加一个体现当前品级的 属性。为确保每次开始新游戏时都重置品级,在reset_stats() 中初始化它:
game_stats.py
  1.    def reset_stats(self):
  2.         """初始化随游戏进行可能变化的统计信息。"""
  3.         self.ships_left = self.settings.ship_limit
  4.         self.score = 0
  5.         self.level = 1
复制代码
为了让Scoreboard 体现当前品级,在__init__() 中调用一个新方法 prep_level() :
scoreboard.py
  1. def __init__(self, ai_game):
  2.         --snip--
  3.         self.prep_high_score()
  4.         self.prep_level()
复制代码
prep_level() 的代码如下:
scoreboard.py
  1. def prep_level(self):
  2.           """将等级转换为渲染的图像。"""
  3.           level_str = str(self.stats.level)
  4.           self.level_image = self.font.render(level_str, True,    #1
  5.                   self.text_color, self.settings.bg_color)
  6.           # 将等级放在得分下方。
  7.           self.level_rect = self.level_image.get_rect()
  8.           self.level_rect.right = self.score_rect.right           #2
  9.           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
  1. def show_score(self):
  2.         """在屏幕上显示得分和等级。"""
  3.         self.screen.blit(self.score_image, self.score_rect)
  4.         self.screen.blit(self.high_score_image, self.high_score_rect)
  5.         self.screen.blit(self.level_image, self.level_rect)
复制代码
新增的代码行在屏幕上体现品级图像。 我们在_check_bullet_alien_collisions() 中进步品级并更新品级图像:
alien_invasion.py
  1. def _check_bullet_alien_collisions(self):
  2.         --snip--
  3.         if not self.aliens:
  4.             # 删除现有的子弹并新建一群外星人。
  5.             self.bullets.empty()
  6.             self._create_fleet()
  7.             self.settings.increase_speed()
  8.             # 提高等级。
  9.             self.stats.level += 1
  10.             self.sb.prep_level()
复制代码
如果整群外星人都被清除,就将stats.level 的值加1,并调用prep_level() 确保正确地体现了新品级。 为确保在开始新游戏时更新品级图像,还需在玩家单击按钮Play时调用 prep_level() : alien_invasion.py
  1. def _check_play_button(self, mouse_pos):
  2.         --snip--
  3.          if button_clicked and not self.stats.game_active:
  4.              --snip--
  5.              self.sb.prep_score()
  6.              self.sb.prep_level()
  7.              --snip--
复制代码
1.3.10体现余下的飞船数


起首,须要让Ship 继承Sprite ,以便创建飞船编组:
ship.py
  1. import pygame
  2.   from pygame.sprite import Sprite
  3.   class Ship(Sprite):                            #1
  4.       """管理飞船的类。"""
  5.       def __init__(self, ai_game):
  6.           """初始化飞船并设置其起始位置。"""
  7.          super().__init__()                      #2
  8.           --snip--
复制代码
这里导入了Sprite ,让Ship 继承Sprite (#1),并在__init__() 的开头 调用super() (#2)。
接下来,须要修改Scoreboard ,以创建可供体现的飞船编组。下面是此中的 import 语句: scoreboard.py
  1. import pygame.font
  2. from pygame.sprite import Group
  3. from ship import Ship
复制代码
鉴于须要创建飞船编组,导入Group 和Ship 类。 下面是方法__init__() : scoreboard.py
  1. def __init__(self, ai_game):
  2.         """初始化记录得分的属性。"""
  3.         self.ai_game = ai_game
  4.         self.screen = ai_game.screen
  5.         --snip--
  6.         self.prep_level()
  7.         self.prep_ships()
复制代码
在调用 prep_level() 后调用了prep_ships() 。 prep_ships() 的代码如下:
scoreboard.py
  1. def prep_ships(self):
  2.          """显示还余下多少艘飞船。"""
  3.          self.ships = Group()                               #1        
  4.          for ship_number in range(self.stats.ships_left):   #2
  5.              ship = Ship(self.ai_game)
  6.              ship.rect.x = 10 + ship_number * ship.rect.width #3
  7.              ship.rect.y = 10                                 #4
  8.              self.ships.add(ship)                             #5
复制代码
方法prep_ships() 创建一个空编组self.ships ,用于存储飞船实例(#1)。为添补这个编组,根据玩家尚有多少艘飞船以相应的次数运行一个循环(#2)。在这个循环中,创建新飞船并设置其 坐标,让整个飞船编组都位于屏幕左 边,且每艘飞船的左边距都为10像素(#3)。还将 坐标设置为离屏幕上边沿10像 素,让全部飞船都出现在屏幕左上角(#4)。末了,将每艘新飞船都添加到编组 ships 中(#5)。
scoreboard.py
  1. def show_score(self):
  2.         """在屏幕上绘制得分、等级和余下的飞船数。"""
  3.         self.screen.blit(self.score_image, self.score_rect)
  4.         self.screen.blit(self.high_score_image, self.high_score_rect)
  5.         self.screen.blit(self.level_image, self.level_rect)
  6.         self.ships.draw(self.screen)
复制代码
为在屏幕上体现飞船,对编组调用draw() 。Pygame将绘制每艘飞船。 为在游戏开始时让玩家知道自己有多少艘飞船,在开始新游戏时调用 prep_ships() 。这是在AlienInvasion 的_check_play_button() 中举行 的:
alien_invasion.py
  1.    def _check_play_button(self, mouse_pos):
  2.         --snip--
  3.      if button_clicked and not self.stats.game_active:
  4.          --snip--
  5.          self.sb.prep_score()
  6.          self.sb.prep_level()
  7.          self.sb.prep_ships()
  8.          --snip--
复制代码
还要在飞船被外星人撞到时调用prep_ships() ,从而在玩家丧失飞船时更新飞船 图像: alien_invasion.py
  1. def _ship_hit(self):
  2.         """响应飞船被外星人撞到。"""
  3.         if self.stats.ships_left > 0:
  4.             #将ships_left减1并更新记分牌。
  5.             self.stats.ships_left -= 1
  6.             self.sb.prep_ships()
  7.             --snip--
复制代码
这里在将ships_left 的值减1后调用prep_ships() 。如许每次丧失飞船后,显 示的飞船数都是正确的。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表