Python应用实例(一)外星人入侵(五)

外星人入侵(五)

  • 1.项目回顾
  • 2.创建第一个外星人
    • 2.1 创建Alien类
    • 2.2 创建Alien实例
  • 3.创建一群外星人
    • 3.1 确定一行可容纳多少个外星人
    • 3.2 创建一行外星人
    • 3.3 重构_create_fleet()
    • 3.4 添加行

在游戏《外星人入侵》中添加外星人。我们将首先在屏幕上边缘附近添加一个外星人,再生成一群外星人。然后让这群外星人向两边和下面移动,并删除被子弹击中的外星人。最后,显示玩家拥有的飞船数量,并在玩家的飞船用完后结束游戏。

1.项目回顾

开发大型项目时,要在进入每个开发阶段之前回顾一下开发计划,搞清楚接下来要通过编写代码来完成哪些任务。本章涉及以下内容。

▲ 研究既有代码,确定实现新功能前是否要重构。
▲ 在屏幕左上角添加一个外星人,并指定合适的边距。
▲ 根据第一个外星人的边距和屏幕尺寸计算屏幕上可容纳多少个外星人。编写一个循环来创建一系列外星人,使其填满屏幕的上半部分。

▲ 让外星人群向两边和下方移动,直到外星人被全部击落、有外星人撞到飞船或有外星人抵达屏幕底端。如果整群外星人都被击落,将再创建一群外星人。如果有外星人撞到了飞船或抵达屏幕底端,将销毁飞船并再创建一群外星人。
▲ 限制玩家可用的飞船数量。当配给的飞船用完之后,游戏将结束。

我们将在实现功能的同时完善这个计划,但就目前而言,该计划已足够详尽。

在项目中添加新功能前,还应审核既有代码。每进入一个新阶段,项目通常会更复杂,因此最好对混乱或低效的代码进行清理。我们一直在不断重构,因此当前没有需要重构的代码。

2.创建第一个外星人

在屏幕上放置外星人与放置飞船类似。每个外星人的行为都由Alien类控制,我们将像创建Ship类那样创建这个类。出于简化考虑,也将使用位图来表示外星人。你可以自己寻找表示外星人的图像。这幅图像的背景为灰色,与屏幕背景色一致。请务必将选择的图像文件保存到文件夹images中。

在这里插入图片描述

2.1 创建Alien类

下面来编写Alien类并将其保存为文件alien.py:

alien.py

  import pygamefrom pygame.sprite import Spriteclass Alien(Sprite):"""表示单个外星人的类。"""def __init__(self, ai_game):"""初始化外星人并设置其起始位置。"""super().__init__()self.screen = ai_game.screen# 加载外星人图像并设置其rect属性self.image = pygame.image.load('images/alien.bmp')self.rect = self.image.get_rect()# 每个外星人最初都在屏幕左上角附近。
❶         self.rect.x = self.rect.widthself.rect.y = self.rect.height# 存储外星人的精确水平位置。
❷         self.x = float(self.rect.x)

除位置不同外,这个类的大部分代码与Ship类相似。每个外星人最初都位于屏幕左上角附近。将每个外星人的左边距都设置为外星人的宽度,并将上边距设置为外星人的高度(见❶),这样更容易看清。我们主要关心的是外星人的水平速度,因此精确地记录了每个外星人的水平位置(见❷)。

Alien类不需要一个在屏幕上绘制外星人的方法,因为我们将使用一个Pygame编组方法,自动在屏幕上绘制编组中的所有元素。

2.2 创建Alien实例

要让第一个外星人在屏幕上现身,需要创建一个Alien实例。这属于设置工作,因此将把这些代码放在AlienInvasion类的方法__init__()末尾。我们最终会创建一群外星人,涉及的工作量不少,因此将新建一个名为_create_fleet()的辅助方法。

在类中,方法的排列顺序无关紧要,只要按统一的标准排列就行。我们将把_create_fleet()放在_update_screen()前面,不过放在AlienInvasion类的任何地方其实都可行。首先,需要导入Alien类。

下面是alien_invasion.py中修改后的import语句:

alien_invasion.py

--snip--
from bullet import Bullet
from alien import Alien

下面是修改后的方法__init__():

alien_invasion.py

    def __init__(self):--snip--self.ship = Ship(self)self.bullets = pygame.sprite.Group()self.aliens = pygame.sprite.Group()self._create_fleet()

创建了一个用于存储外星人群的编组,还调用了接下来将编写的方法_create_fleet()。

下面是新编写的方法_create_fleet():

alien_invasion.py

    def _create_fleet(self):"""创建外星人群。"""# 创建一个外星人。alien = Alien(self)self.aliens.add(alien)

在这个方法中,创建了一个Alien实例,再将其添加到用于存储外星人群的编组中。外星人默认放在屏幕左上角附近,对第一个外星人来说,这样的位置非常合适。

要让外星人现身,需要在_update_screen()中对外星人编组调用方法draw():

alien_invasion.py

    def _update_screen(self):--snip--for bullet in self.bullets.sprites():bullet.draw_bullet()self.aliens.draw(self.screen)pygame.display.flip()

对编组调用draw()时,Pygame将把编组中的每个元素绘制到属性rect指定的位置。方法draw()接受一个参数,这个参数指定了要将编组中的元素绘制到哪个surface上。图显示了在屏幕上现身的第一个外星人。

在这里插入图片描述

第一个外星人正确地现身了,下面来编写绘制一群外星人的代码。

3.创建一群外星人

要绘制一群外星人,需要确定一行能容纳多少个外星人以及要绘制多少行。我们将首先计算外星人的水平间距并创建一行外星人,再确定可用的垂直空间并创建整群外星人。

3.1 确定一行可容纳多少个外星人

为确定一行可容纳多少个外星人,来看看可用的水平空间有多大。屏幕宽度存储在settings.screen_width中,但需要在屏幕两边都留下一定的边距(将其设置为外星人的宽度)。因为有两个边距,所以可用于放置外星人的水平空间为屏幕宽度减去外星人宽度的两倍:

available_space_x = settings.screen_width – (2 * alien_width)

还需要在外星人之间留出一定的空间,不妨将其定为外星人的宽度。因此,显示一个外星人所需的水平空间为外星人宽度的两倍:一个宽度用于放置外星人,另一个宽度为外星人右边的空白区域。为确定一行可容纳多少个外星人,将可用空间除以外星人宽度的两倍。我们使用整除(floor division)运算符//,它将两个数相除并丢弃余数,让我们得到一个表示外星人个数的整数。

number_aliens_x = available_space_x // (2 * alien_width)

我们将在创建外星人群时使用这些公式。

注意 令人欣慰的是,在程序中执行计算时,无须在一开始确定公式是正确的,而是可以尝试运行程序,看看结果是否符合预期。即便是在最坏的情况下,也只是屏幕上显示的外星人太多或太少。随后可根据在屏幕上看到的情况调整计算公式。

3.2 创建一行外星人

现在可以创建整行外星人了。由于创建单个外星人的代码管用,我们重写_create_fleet()使其创建一行外星人:

alien_invasion.py

      def _create_fleet(self):"""创建外星人群。"""# 创建一个外星人并计算一行可容纳多少个外星人。# 外星人的间距为外星人宽度。
❶         alien = Alien(self)
❷         alien_width = alien.rect.width
❸         available_space_x = self.settings.screen_width - (2 * alien_width)number_aliens_x = available_space_x // (2 * alien_width)# 创建第一行外星人。for alien_number in range(number_aliens_x):# 创建一个外星人并将其加入当前行。alien = Alien(self)
❺             alien.x = alien_width + 2 * alien_width * alien_numberalien.rect.x = alien.xself.aliens.add(alien)

这些代码大多在前面详细介绍过。为放置外星人,需要知道外星人的宽度和高度,因此在执行计算前,创建一个外星人(见❶)。这个外星人不是外星人群的成员,因此没有将其加入编组aliens中。在❷处,从外星人的rect属性中获取外星人宽度,并将这个值存储到alien_width中,以免反复访问属性rect。在❸处,计算可用于放置外星人的水平空间以及其中可容纳多少个外星人。

接下来,编写一个循环,从零数到要创建的外星人数(见❹)。在这个循环中,创建一个新的外星人,并通过设置[插图]坐标将其加入当前行(见❺)。将每个外星人都往右推一个外星人宽度。接下来,将外星人宽度乘以2,得到每个外星人占据的空间(其中包括右边的空白区域),再据此计算当前外星人在当前行的位置。我们使用外星人的属性x来设置其rect的位置。最后,将每个新创建的外星人都添加到编组aliens中。

如果现在运行这个游戏,将看到第一行外星人,如图所示。

在这里插入图片描述

这行外星人在屏幕上稍微偏向了左边、这实际上是有好处的,因为后面将让外星人群往右移,触及屏幕边缘后稍微往下移,再往左移,依此类推。就像经典游戏《太空入侵者》,相比于只往下移,这种移动方式更为有趣。我们将让外星人群不断这样移动,直到所有外星人都被击落,或者有外星人撞上飞船或抵达屏幕底端。

3.3 重构_create_fleet()

倘若只需使用前面的代码就能创建外星人群,也许应该让_create_fleet()保持原样,但鉴于创建外星人群的工作还未完成,我们稍微整理一下这个方法。为此,添加辅助方法_create_alien(),并在_create_fleet()中调用它:

alien_invasion.py

    def _create_fleet(self):--snip--# 创建第一行外星人。for alien_number in range(number_aliens_x):self._create_alien(alien_number)def _create_alien(self, alien_number):"""创建一个外星人并将其放在当前行。"""alien = Alien(self)alien_width = alien.rect.widthalien.x = alien_width + 2 * alien_width * alien_numberalien.rect.x = alien.xself.aliens.add(alien)

除self外,方法_create_alien()还接受另一个参数,即要创建的外星人的编号。该方法的代码与_create_fleet()相同,但在内部获取外星人宽度,而不是将其作为参数传入。这样重构后,添加新行进而创建整群外星人将更容易。

3.4 添加行

要创建外星人群,需要计算屏幕可容纳多少行,并将创建一行外星人的循环重复执行相应的次数。为计算可容纳的行数,要先计算可用的垂直空间:用屏幕高度减去第一行外星人的上边距(外星人高度)、飞船的高度以及外星人群最初与飞船之间的距离(外星人高度的两倍):

available_space_y = settings.screen_height – (3 * alien_height) – ship_height

这将在飞船上方留出一定的空白区域,给玩家留出射杀外星人的时间。

每行下方都要留出一定的空白区域,不妨将其设置为外星人的高度。为计算可容纳的行数,将可用的垂直空间除以外星人高度的两倍。我们使用整除,因为行数只能是整数。(同样,如果这样的计算不对,我们马上就能发现,继而将间距调整为合理的值。)

number_rows = available_space_y // (2 * alien_height)

知道可容纳多少行之后,便可重复执行创建一行外星人的代码了:

alien_invasion.py

      def _create_fleet(self):--snip--alien = Alien(self)
❶         alien_width, alien_height = alien.rect.sizeavailable_space_x = self.settings.screen_width - (2 * alien_width)number_aliens_x = available_space_x // (2 * alien_width)#计算屏幕可容纳多少行外星人。ship_height = self.ship.rect.height
❷         available_space_y = (self.settings.screen_height -(3 * alien_height) - ship_height)number_rows = available_space_y // (2 * alien_height)# 创建外星人群。for row_number in range(number_rows):for alien_number in range(number_aliens_x):self._create_alien(alien_number, row_number)def _create_alien(self, alien_number, row_number):"""创建一个外星人,并将其放在当前行。"""alien = Alien(self)alien_width, alien_height = alien.rect.sizealien.x = alien_width + 2 * alien_width * alien_numberalien.rect.x = alien.x
❹         alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_numberself.aliens.add(alien)

需要知道外星人的宽度和高度,因此在❶处使用了属性size。该属性是一个元组,包含rect对象的宽度和高度。为计算屏幕可容纳多少行外星人,在计算available_space_x的代码后面添加了计算available_space_y的代码(见❷)。此处将计算公式用圆括号括起来,以便将代码分成两行,遵循每行不超过79字符的建议。

为创建多行外星人,使用了两个嵌套在一起的循环:一个外部循环和一个内部循环(见❸)。内部循环创建一行外星人,而外部循环从零数到要创建的外星人行数:Python将重复执行创建单行外星人的代码,重复次数为number_rows。

为嵌套循环,编写了一个新的for循环,并缩进了要重复执行的代码。(在大多数文本编辑器中,缩进代码块和取消缩进都很容易,详情请参阅附录B)。现在调用_create_alien()时,传递了一个表示行号的实参,将每行都沿屏幕依次向下放置。

在_create_alien()的定义中,需要一个用于存储行号的形参。在_create_alien()中,修改外星人的[插图]坐标(见❹)并在第一行外星人上方留出与外星人等高的空白区域。相邻外星人行的[插图]坐标相差外星人高度的两倍,因此将外星人高度乘以2,再乘以行号。第一行的行号为0,因此第一行的垂直位置不变,而其他行都沿屏幕依次向下放置。

如果现在运行这个游戏,将看到一群外星人,如图:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/13938.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cannot find tomcat-9.0.0.M21/bin/setclasspath.sh

问题描述:将linux上的tomcat直接拷贝到以一个路径下,执行sh startup.sh 报错 解决:修改全局变量配置文件 1、vim /etc/profile (主要修改如下图所标记的值 ) 2、source /etc/profile (设置环境变量立即…

C. Vampiric Powers, anyone? - 思维+前缀和

分析: 添加新元素的操作可以理解为添加任意一段以n结尾的异或和,当原数组总异或和与新加的元素进行异或又可以得到剩余的前缀的异或和,假设新加的元素的值是i到n的异或和x,那么总异或和sumpre^x,所以sum^xpre&#xff…

ChatGPT 话题相关和类 ChatGPT 工具 | 优质文章、相关论文、应用、学习资源整理

文章目录 一、前言二、主要内容三、总结 🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 人工智能与手机和互联网一样具有革命性。 2023 年已经过去一半,ChatGPT 在今年以来一直备受瞩目。目前 ChatGPT 的更新速度逐渐放缓&#…

Spring Boot的Maven插件Spring Boot Maven plugin详解

1.Spring Boot的Maven插件Spring Boot Maven plugin详解 2.Maven插件之git-commit-id-plugin

Devops系列五(CI篇之pipeline libraray)jenkins将gitlab helm yaml和argocd 串联,自动部署到K8S

一、说在前面的话 本文是CI篇的上文,因为上一篇已经作了总体设计,就不再赘述,有需要的请看前文。 我们将演示,使用CI工具–jenkins,怎么和CD工具–argocd串联,重点是在Jenkins该怎么做。准备工作和argocd等…

AI在金融领域的应用

AI金融领域 信贷业务 个人信贷单笔数额小、数量大,需要大量的人力和时间投入,信贷审核的数据也呈现出分散化、碎片化的特点。同时传统金融机构和互联网金融公司的风控环节中,普遍存在信息不对称、成本高、时效性差、效率低等问题&#xff0c…

2.1.cuda驱动API-概述

目录 前言1. Driver API概述2. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程,之前有看过一遍,但是没有做笔记,很多东西也忘了。这次重新撸一遍,顺便记记笔记 本次课程学习精简 CUDA 教程-Driver API 概述 课程…

医学图像增强系统的设计_kaic

目录 1绪论 1.1课题背景 1.2医学图像增强以及相关理论的现状2 1.3本文内容安排 2图像增强技术 2.1空域增强方法 2.1.1空域点运算增强方法 2.1.2空域滤波增强方法 2.2频域增强算法 2.2.1低通滤波 2.2.2高通滤波 2.2.3同态滤波 2.3本章小结 3医学图像增强算法 3.1医学图像的特点 …

【C语言】深入学习数组

👦个人主页:Weraphael ✍🏻作者简介:目前正在回炉重造C语言(2023暑假) ✈️专栏:【C语言航路】 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你…

多模态系列论文--BEiT-3 详细解析

论文地址:Image as a Foreign Language: BEIT Pretraining for All Vision and Vision-Language Tasks 论文代码:BEiT-3 BEiT-3 1 引言:Big Convergence(大一统)2 BEIT-3预训练框架3 下游任务实现框架4 实验效果5 总结…

系统提权与数据窃取

系统提权与数据窃取 一、后渗透二、后渗透的技术2.1、提权2.2、横向移动2.3、持久化2.4、数据窃取2.5、漏洞利用 三、meterpreter后渗透3.1、靶机权限提升3.1.1、windows内核/服务漏洞3.1.2、bypassUAC3.1.2.1、bypassuac 进程注入3.1.2.2、bypassuac_injection 内存注入3.1.2.…

基于Tensorflow和Keras实现卷积神经网络CNN并进行猫狗识别

文章目录 一、环境配置1、安装Anaconda2、配置TensorFlow、Keras 二、猫狗数据集分类建模3.1 猫狗图像预处理3.2 猫狗分类的实例——基准模型3.1 构建神经网络3.2 配置优化器3.3 图片格式转化3.4 训练模型3.5 保存模型3.6 可视化 三、数据增强四、dropout 层五、参考资料 一、环…