已解决:为什么移动的外星人只有一列了?【python入门到实践13章】
已解决:为什么移动的外星人只有一列了?【python入门到实践13章】
Mark
这几日,在跟着《python入门到实践》一书,写一个“外星人入侵”的pygame游戏,本以为很简单(确实不难),但是却因为一个小问题困住了我好几天!茶不思饭不想,到底是哪里出了问题呀,今天终于找到了解决方案,可能有一些同学和我遇到的情况一样,所以在这里mark一下以共飨!
问题描述
为什么移动的外星人只有一列了?
为什么在静止的外星人是全的?
刚开始,我也是一头雾水,论坛里也有同学问到同样的问题,但是没有给出详细的解释
譬如这位同学@qq_43578746
@问题原址[link]https://ask.csdn.net/questions/706442
问题解析
说完了问题的描述,我们来看一下问题到底出在哪里?
实际上,我们通过对比问题的描述,可以很肯定的是,问题出在实现外星人移动的方法上
我们把几个和外星人移动的代码块贴上来分析一下。
先看下主函数中实现外星人移动的过程
import ··· def run_game(): ''' 初始化游戏并创建一个屏幕对象 ''' pygame.init() *---snip---* # 创建一个外星人编组 aliens = Group() # 创建外星人群 gf.create_fleet(ai_setting, screen, aliens, ship) # 开始游戏的主循环 while True: *---snip---* gf.update_aliens(ai_setting, screen, aliens, ship) gf.update_screen(ai_setting, screen, ship, aliens, bullets) run_game()
看一下game_functions中和外星人移动相关的方法
import ··· *---snip---* def update_aliens(ai_setting, screen, aliens, ship): # 更新外星人的位置 check_fleet_edges(ai_setting, aliens) aliens.update() def create_alien(ai_setting, screen, aliens, alien_number, row_number): # 创建一个外星人,并放在当前行 alien = Alien(ai_setting, screen) alien_width = alien.rect.width alien.rect.x = alien_width + 2 * alien_width * alien_number alien.rect.y = alien.rect.height + 1.5 * alien.rect.height * row_number aliens.add(alien)
再来看一下外星人类的update方法
import ··· class Alien(Sprite): def __init__(self, ai_setting, screen): super(Alien, self).__init__() *---snip---* # 最初的外星人都在屏幕的最左边的位置 self.rect.x = self.rect.width self.rect.y = self.rect.height # 存储外星人的精确位置 self.x = float(self.rect.x) def update(self): self.x += (self.ai_setting.alien_speed_factor * self.ai_setting.fleet_direction) # self.x += self.ai_setting.alien_speed_factor self.rect.x = self.x
开始解决问题了哈!
让我先来抖个机灵,你是不是也为了 ‘偷懒’, 在game_functions的create_alien的方法中也想这样写的?
def create_alien(ai_setting, screen, aliens, alien_number, row_number): # 创建一个外星人,并放在当前行 alien = Alien(ai_setting, screen) alien_width = alien.rect.width alien.rect.x = alien_width + 2 * alien_width * alien_number alien.rect.y = alien.rect.height + 1.5 * alien.rect.height * row_number aliens.add(alien)
好的,问题找到了!就是在这里!
我们来看下,书里是怎么写的
先说明,alien.rect.x 才是绘制外星人所需要的图像坐标,alien.x是为了精确图形位置所用的(实际上在绘图时没有用)
def create_alien(ai_settings, screen, aliens, alien_number, row_number): """Create an alien, and place it in the row.""" alien = Alien(ai_settings, screen) alien_width = alien.rect.width alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = alien.x alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number aliens.add(alien)
发现了吗,书中是特别写了
alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = alien.x
我刚开始在写这里的时候,也是觉得奇怪?咦,为什么alien.rect.y直接赋值,而alien.rect.x却要先赋值alien.x在进行二次赋值呢?
在上面的alien类中,像前面所说,我们知道,alien.x是为了精确图形位置所用的,但是在绘制静止的外星人图像的时候,这个参数实际上是没有用到的,所以不会出现任何问题。alien.rect.y自然不用说,这个确定垂直位置的参数,至始至终也没有使用精确位置。
之所以会在实现移动的过程中出现问题,是因为在alien类的update方法中是这样写的:
def update(self): self.x += (self.ai_setting.alien_speed_factor * self.ai_setting.fleet_direction) self.rect.x = self.x
看到了吗?
如果是按照这样写
def create_alien(ai_settings, screen, aliens, alien_number, row_number): alien = Alien(ai_settings, screen) alien.rect.x = alien_width + 2 * alien_width * alien_number
和按照这样写
def create_alien(ai_settings, screen, aliens, alien_number, row_number): alien = Alien(ai_settings, screen) alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = alien.x
赋值的顺序是不一样的。
解释一下第一种函数为什么错了:
函数过程:
先初始化一个alien实例,此时
self.rect.x = self.rect.width,(假设等于60)
self.x = float(self.rect.x)(60.0)
所以根据
class Alien(Sprite) # 最初的外星人都在屏幕的最左边的位置 self.rect.x = self.rect.width # 存储外星人的精确位置 self.x = float(self.rect.x)
初始化化完成后,开始赋值
alien.rect.x = alien_width + 2 * alien_width * alien_number(某个数值 60 + 2 * 60 * 1=180)
而此时alien.x还是为60.0
随后,每一个循环
alien.rect.x = alien_width + 2 * alien_width * alien_number(新的某个数值)
而alien.x一直是为60.0,(因为一直是初始化给alien.x赋的值,所以一直是60.0)
在update中,却一直用self.rect.x = self.x,所以最后在调用update的时候,所有的alien.rect.x就全部变成了60,
导致最后状况就是,实际上每行产生了多个外星人,但每行却只显示了一个(多个外星人重叠了)
现在明白了吧!不是create_fleet出了问题,而是忽略了self.rect.x和 self.x的差异!
解决方案
第一种就是按照书上的写法,先赋值alien.x,再赋值alien.rect.x
如下:
def create_alien(ai_settings, screen, aliens, alien_number, row_number): alien = Alien(ai_settings, screen) alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = alien.x
第二种就是,在update方法中,直接修改为(但是这种,就不会用到self.x,也就不能精确描述位置了):
def update(self): self.rect.x += (self.ai_setting.alien_speed_factor * self.ai_setting.fleet_direction) # self.x += self.ai_setting.alien_speed_factor #self.rect.x = self.x
写到这里问题就已经解决了,有什么问题,我们可以评论交流~
- [置顶] python爬虫实践——零基础快速入门(六)解决动态页面爬取问题
- Python从入门到实践-外星人入侵完整代码
- python编程:从入门到实践PDF——带完整书签
- 为什么说python入门很简单,但是在你这很难?
- python_tweets.json (python数据挖掘入门与实践数据集下载)
- Python 从入门到实践 8-12 课后习题
- python 从入门到实践 第五章习题 (高级编程技巧 week3-1)
- Python网页抓取与爬虫基本实践-入门篇
- Python编程:从入门到实践 学习笔记 基础知识(六)函数
- Python入门与实践 Chapter 7 动手试一试
- python编程:从入门到实践-第十章练习
- 为什么自学Python看不进去?0基础入门Python有哪些捷径?
- python从入门到实践 第六章习题 (高级编程技术 week3-2)
- python从入门到实践:9-6 冰淇淋小店
- python 编程从入门到实践11章 测试代码 11.2测试类11.2.2 修改
- python从入门到实践chapter09
- 分享《Python数据挖掘入门与实践》高清中文版+高清英文版+源代码
- Python入门与实践 Chapter 6 动手试一试
- python从入门到实践 第八章习题(高级编程技术 week4-2)
- 支持度与置信度(基本示例)--《python数据挖掘入门与实践》