您的位置:首页 > 编程语言 > Python开发

已解决:为什么移动的外星人只有一列了?【python入门到实践13章】

2019-02-26 19:39 417 查看

已解决:为什么移动的外星人只有一列了?【python入门到实践13章】

Mark

这几日,在跟着《python入门到实践》一书,写一个“外星人入侵”的pygame游戏,本以为很简单(确实不难),但是却因为一个小问题困住了我好几天!茶不思饭不想,到底是哪里出了问题呀,今天终于找到了解决方案,可能有一些同学和我遇到的情况一样,所以在这里mark一下以共飨!

问题描述

为什么移动的外星人只有一列了?
为什么在静止的外星人是全的?
刚开始,我也是一头雾水,论坛里也有同学问到同样的问题,但是没有给出详细的解释
譬如这位同学@qq_43578746
@问题原址[link]https://ask.csdn.net/questions/706442

(图1 原论坛问题)

(图2 移动的外星人只有一列)

(图3 静止的外星人是布满屏幕的)

问题解析

说完了问题的描述,我们来看一下问题到底出在哪里?
实际上,我们通过对比问题的描述,可以很肯定的是,问题出在实现外星人移动的方法上
我们把几个和外星人移动的代码块贴上来分析一下。
先看下主函数中实现外星人移动的过程

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

写到这里问题就已经解决了,有什么问题,我们可以评论交流~

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: