关于“Python”的核心知识点整理大全34

目录

第13 章

外星人

13.1 回顾项目

game_functions.py

13.2 创建第一个外星人

13.2.1 创建 Alien 类

alien.py

13.2.2 创建 Alien 实例

alien_invasion.py

13.2.3 让外星人出现在屏幕上

game_functions.py

13.3 创建一群外星人

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

注意

13.3.2 创建多行外星人

alien_invasion.py

game_functions.py

13.3.3 创建外星人群

game_functions.py

注意


第13 章

外星人

13.1 回顾项目

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

 研究既有代码,确定实现新功能前是否要进行重构。

 在屏幕左上角添加一个外星人,并指定合适的边距。

 根据第一个外星人的边距和屏幕尺寸计算屏幕上可容纳多少个外星人。我们将编写一个 循环来创建一系列外星人,这些外星人填满了屏幕的上半部分。

 让外星人群向两边和下方移动,直到外星人被全部击落,有外星人撞到飞船,或有外星 人抵达屏幕底端。如果整群外星人都被击落,我们将再创建一群外星人。如果有外星人 撞到了飞船或抵达屏幕底端,我们将销毁飞船并再创建一群外星人。

 限制玩家可用的飞船数量,配给的飞船用完后,游戏结束。

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

在给项目添加新功能前,还应审核既有代码。每进入一个新阶段,通常项目都会更复杂,因 此最好对混乱或低效的代码进行清理。

我们在开发的同时一直不断地重构,因此当前需要做的清理工作不多,但每次为测试新功能而运行这个游戏时,都必须使用鼠标来关闭它,这太讨厌了。下面来添加一个结束游戏的快捷键Q:

game_functions.py
def check_keydown_events(event, ai_settings, screen, ship, bullets):
 --snip--
 elif event.key == pygame.K_q:
 sys.exit() 

在check_keydown_events()中,我们添加了一个代码块,以便在玩家按Q时结束游戏。这样 的修改很安全,因为Q键离箭头键和空格键很远,玩家不小心按Q键而导致游戏结束的可能性不 大。现在测试时可按Q关闭游戏,而无需使用鼠标来关闭窗口了。

13.2 创建第一个外星人

在屏幕上放置外星人与放置飞船类似。每个外星人的行为都由Alien类控制,我们将像创建 Ship类那样创建这个类。出于简化考虑,我们也使用位图来表示外星人。你可以自己寻找表示外 星人的图像,也可使用图13-1所示的图像,可在本书配套资源(https://www.nostarch.com/ pythoncrashcourse/)中找到。这幅图像的背景为灰色,与屏幕背景色一致。请务必将你选择的图 像文件保存到文件夹images中。

13.2.1 创建 Alien 类

下面来编写Alien类:

alien.py
import pygame
from pygame.sprite import Sprite 
class Alien(Sprite):
 """表示单个外星人的类"""
 def __init__(self, ai_settings, screen):
 """初始化外星人并设置其起始位置"""
 super(Alien, self).__init__()
 self.screen = screen
 self.ai_settings = ai_settings
 # 加载外星人图像,并设置其rect属性
 self.image = pygame.image.load('images/alien.bmp')
 self.rect = self.image.get_rect()
 # 每个外星人最初都在屏幕左上角附近
1 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)

除位置不同外,这个类的大部分代码都与Ship类相似。每个外星人最初都位于屏幕左上 角附近,我们将每个外星人的左边距都设置为外星人的宽度,并将上边距设置为外星人的高 度(见1)。

13.2.2 创建 Alien 实例

下面在alien_invasion.py中创建一个Alien实例:

alien_invasion.py
--snip--
from ship import Ship
from alien import Alien
import game_functions as gf
def run_game():
 --snip--
 # 创建一个外星人
 alien = Alien(ai_settings, screen)
 # 开始游戏主循环
 while True:
 gf.check_events(ai_settings, screen, ship, bullets)
 ship.update()
 gf.update_bullets(bullets)
 gf.update_screen(ai_settings, screen, ship, alien, bullets)
run_game()

在这里,我们导入了新创建的Alien类,并在进入主while循环前创建了一个Alien实例。我们 没有修改外星人的位置,因此该while循环没有任何新东西,但我们修改了对update_screen()的 调用,传递了一个外星人实例。

13.2.3 让外星人出现在屏幕上

为让外星人出现在屏幕上,我们在update_screen()中调用其方法blitme():

game_functions.py
def update_screen(ai_settings, screen, ship, alien, bullets):
 --snip--
 # 在飞船和外星人后面重绘所有的子弹
 for bullet in bullets:
 bullet.draw_bullet()
 ship.blitme()
 alien.blitme()
 # 让最近绘制的屏幕可见
 pygame.display.flip()

我们先绘制飞船和子弹,再绘制外星人,让外星人在屏幕上位于最前面。图13-2显示了屏幕 上的第一个外星人。

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

13.3 创建一群外星人

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

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

为确定一行可容纳多少个外星人,我们来看看可用的水平空间有多大。屏幕宽度存储在 ai_settings.screen_width中,但需要在屏幕两边都留下一定的边距,把它设置为外星人的宽度。 由于有两个边距,因此可用于放置外星人的水平空间为屏幕宽度减去外星人宽度的两倍:

available_space_x = ai_settings.screen_width – (2 * alien_width)

我们还需要在外星人之间留出一定的空间,即外星人宽度。因此,显示一个外星人所需的水 平空间为外星人宽度的两倍:一个宽度用于放置外星人,另一个宽度为外星人右边的空白区域。 为确定一行可容纳多少个外星人,我们将可用空间除以外星人宽度的两倍:

number_aliens_x = available_space_x / (2 * alien_width) 

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


注意

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


13.3.2 创建多行外星人

为创建一行外星人,首先在alien_invasion.py中创建一个名为aliens的空编组,用于存储全部 外星人,再调用game_functions.py中创建外星人群的函数:

alien_invasion.py
import pygame
from pygame.sprite import Group
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
 --snip--
 # 创建一艘飞船、一个子弹编组和一个外星人编组
 ship = Ship(ai_settings, screen)
 bullets = Group() 
1 aliens = Group()
 # 创建外星人群
2 gf.create_fleet(ai_settings, screen, aliens)
 # 开始游戏主循环
 while True:
 --snip—
3 gf.update_screen(ai_settings, screen, ship, aliens, bullets)
run_game()

由于我们不再在alien_invasion.py中直接创建外星人,因此无需在这个文件中导入Alien类。 1处创建了一个空编组,用于存储所有的外星人。接下来,调用稍后将编写的函数 create_fleet()(见2),并将ai_settings、对象screen和空编组aliens传递给它。然后,修改对 update_screen()的调用,让它能够访问外星人编组(见3)。 我们还需要修改update_screen():

game_functions.py
def update_screen(ai_settings, screen, ship, aliens, bullets):
 --snip--
 ship.blitme()
 aliens.draw(screen)
 # 让最近绘制的屏幕可见
 pygame.display.flip() 

对编组调用draw()时,Pygame自动绘制编组的每个元素,绘制位置由元素的属性rect决定。 在这里,aliens.draw(screen)在屏幕上绘制编组中的每个外星人。

13.3.3 创建外星人群

现在可以创建外星人群了。下面是新函数create_fleet(),我们将它放在game_functions. py的末尾。我们还需要导入Alien类,因此务必在文件game_functions.py开头添加相应的import 语句:

game_functions.py
--snip--
from bullet import Bullet
from alien import Alien
--snip--
def create_fleet(ai_settings, screen, aliens):
 """创建外星人群"""
 # 创建一个外星人,并计算一行可容纳多少个外星人
 # 外星人间距为外星人宽度
1 alien = Alien(ai_settings, screen)
2 alien_width = alien.rect.width
3 available_space_x = ai_settings.screen_width - 2 * alien_width
4 number_aliens_x = int(available_space_x / (2 * alien_width))
# 创建第一行外星人
5 for alien_number in range(number_aliens_x):
 # 创建一个外星人并将其加入当前行
6 alien = Alien(ai_settings, screen)
 alien.x = alien_width + 2 * alien_width * alien_number
 alien.rect.x = alien.x
 aliens.add(alien) 

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

相比于前面介绍的工作,这里唯一的不同是使用了int()来确保计算得到的外星人数量为整 数(见4),因为我们不希望某个外星人只显示一部分,而且函数range()也需要一个整数。函数 int()将小数部分丢弃,相当于向下圆整(这大有裨益,因为我们宁愿每行都多出一点点空间, 也不希望每行的外星人之间过于拥挤)。

接下来,我们编写了一个循环,它从零数到要创建的外星人数(见5)。在这个循环的主体 中,我们创建一个新的外星人,并通过设置x坐标将其加入当前行(见6)。将每个外星人都往右 推一个外星人的宽度。接下来,我们将外星人宽度乘以2,得到每个外星人占据的空间(其中包 括其右边的空白区域),再据此计算当前外星人在当前行的位置。最后,我们将每个新创建的外 星人都添加到编组aliens中。 如果你现在运行这个游戏,将看到第一行外星人,如图13-3所示。

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


注意

根据你选择的屏幕宽度,在你的系统中,第一行外星人的位置可能稍有不同


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用PE信息查看工具和Beyond Compare文件比较工具排查dll文件版本不对的问题

目录 1、问题说明 2、修改了代码,但安装版本还是有问题 3、使用PE信息查看工具查看音视频库文件(二进制)的时间戳 4、使用Beyond Compare比较两个库文件的差异 5、找到原因 6、最后 C软件异常排查从入门到精通系列教程(专栏…

小程序面试题 | 10.精选小程序面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

node.js mongoose index(索引)

目录 简介 索引类型 单索引 复合索引 文本索引 简介 在 Mongoose 中,索引(Index)是一种用于提高查询性能的数据结构,它可以加速对数据库中文档的检索操作 索引类型 单索引、复合索引、文本索引、多键索引、哈希索引、地理…

【Jmeter】循环执行某个接口,接口引用的参数变量存在规律变化

变量设置成下面的值即可 ${__V(supplierId_${supplierIdNum})}

机器学习 | K-means聚类

K-means聚类 基本思想 图中的数据可以分成三个分开的点集(称为族),一个能够分出这些点集的算法,就被称为聚类算法 算法概述 K-means算法是一种无监督学习方法,是最普及的聚类算法,算法使用个没有标签的数据集,然后将…

centos开机自启动实战小案例以及注册nacos的jar服务自起

1.编写一个我们需要做事的脚本 #!/bin/bash # 打印 "Hello" echo "Hello,Mr.Phor" # 为了更好的能看到效果 我们把这段文本放置到一个文件中 如果重启能够看到 /a.txt文件 我们实验成功 echo "hahahahahahahaha" > /a.txt #每次开机 执行…

用23种设计模式打造一个cocos creator的游戏框架----(二十三)中介者模式

1、模式标准 模式名称:中介者模式 模式分类:行为型 模式意图:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 结构图&#xff…

Go 随机密码

一.Go实现随机密码 随机密码 package mainimport ("fmt""math/rand""os""strconv""time" )func RandomPassword(num int) {length : numif len(os.Args) > 1 {arg : os.Args[1]i, err : strconv.ParseInt(arg, 10, 6…

aws-waf-cdn 基于规则组的永黑解决方案

1. 新建waf 规则组 2. 为规则组添加规则 根据需求创建不同的规则 3. waf中附加规则组 (此时规则组所有规则都会附加到waf中,但是不会永黑) 此刻,可以选择测试下规则是否生效,测试前确认保护资源绑定无误 4. 创建堆…

[前端优化]项目优化--Lighthouse

[前端优化]项目优化--Lighthouse 前端优化的分类Lighthouse 优化工具优化维度--性能(Performance)性能指标概览白屏时间--FP首字节时间--TTFB首次输入延迟--FID累积布局偏移--CLS 性能指标分析Lighthouse的性能优化方案性能优化实战解析Serve images in next-gen formatsEnable…

阿里云吴结生:云计算是企业实现数智化的阶梯

云布道师 近年来,越来越多人意识到,我们正处在一个数据爆炸式增长的时代。IDC 预测 2027 年全球产生的数据量将达到 291 ZB,与 2022 年相比,增长了近 2 倍。其中 75% 的数据来自企业,每一个现代化的企业都是一家数据公…

LVM-系统

# Linux常见的文件系统:ext4,xfs,vfat(linux和window都能够识别) mkfs.ext4 /dev/sdb1 # 格式化为ext4文件系统 mkfs.xfs /dev/sdb2 # 格式化为xfs文件系统 mkfs.vfat /dev/sdb1 # 格式化为vfat文件系统 mksw…

第3节 二分、复杂度、动态数组、哈希表

二分法 入门题目 有序数组中找到num package class03;import java.util.Arrays; // 有序数组中找到num public class Code_BSExist {// arr保证有序public static boolean find(int[] arr, int num) { // 二分法,有缺陷if (arr null || arr.length 0) { // 边界…

Open3D (C++) 距离计算

目录 一、算法原理1、欧氏距离二、代码实现三、结果展示一、算法原理 1、欧氏距离 在数学中,欧几里得距离或欧几里得度量是欧几里得空间中两点间“普通”(即直线)距离。欧几里得距离有时候有称欧氏距离,在数据分析及挖掘中经常会被使用到,例如聚类或计算相似度。 如果我…

blender径向渐变材质-着色编辑器

要点: 1、用纹理坐标中的物体输出连接映射中的矢量输入 2、物体选择一个空坐标,将空坐标延z轴上移一段距离 3、空坐标的大小要缩放到和要添加材质的物体大小保持一致

【Spring Security】认证密码加密Token令牌CSRF的使用详解

🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《Spring Security》。🎯🎯 …

Ubuntu 常用命令之 sed 命令用法介绍

📑Linux/Ubuntu 常用命令归类整理 sed是一个在Linux和其他Unix-like系统中常用的流编辑器,用于对输入流(文件或管道)进行基本的文本转换。它可以非常方便地进行文本替换、插入、删除等操作。 sed命令的基本格式为 sed [options…

图像处理—小波变换

小波变换 一维小波变换 因为存在 L 2 ( R ) V j 0 ⊕ W j 0 ⊕ W j 0 1 ⊕ ⋯ L^{2}(\boldsymbol{R})V_{j_{0}}\oplus W_{j_{0}}\oplus W_{j_{0}1}\oplus\cdots L2(R)Vj0​​⊕Wj0​​⊕Wj0​1​⊕⋯,所以存在 f ( x ) f(x) f(x)可以在子空间 V j 0 V_{j_0} Vj0…

通讯录应用程序开发指南

目录 一、前言 二、构建通讯录应用程序 2.1通讯录框架 (1)打印菜单 (2) 联系人信息的声明 (3)创建通讯录 (4)初始化通讯录 2.2功能实现 (1)增加联系人 (2)显示联系人 (3)删除联系人 (4)查找联系人 (5)修改联系人 (6)排序联系人 三、通讯录的优化 3.1 文件存储 …

机器学习——分类评价指标

【说明】文章内容来自《机器学习——基于sklearn》,用于学习记录。若有争议联系删除。 1、评价指标 对于模型的评价往往会使用损失函数和评价指标,两者的本质是一致的。一般情况下,损失函数应用于训练过程,而评价指标应用于测试过…