第13章 外星人

13.1 回顾项目

在开发后续程序前回顾当前项目进度。

明确后续开发的目标,做好计划尽量详尽

清理前期代码,需要重构的重构好。

13.2 创建第一个外星人

1、创建Alien类

注意点:screen和settings两个形参,一般在创建角色类的时候都会设定。

self.x = float(self.rect.x)将位置变成浮点型,也是一般操作,用于精确调整位置。

2、创建Alien实例

3、让外星人出现在屏幕上

在game_functions.py中update_screen()方法中调用alien的blitme()方法。

13.3 创建一群外星人

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

两边留白,外星人之间留空,用屏幕宽度减去两边留白再除以两倍外星人宽度

2、创建多行外星人

由于不在alien_invasion.py文件中直接创建外星人,因此无需再这个文件中导入Alien类。同样类比Bullet类,并未在主程序中导入,而是在game_functions.py中导入。

创建一个aliens的空编组,用于存储所有外星人

在game_function中的update_screen()中修改aliens.draw(screen),对编组用draw()方法时,Pygame自动绘制每个元素。

3、创建外星人群

在game_functions.py中创建creat_fleet()函数。文件中导入Alien类。

在creat_fleet()函数中一共创建了两次alien实例(alien=Alien(screen,settings))。第一次在for循环外面,用于获取rect属性计算一行空间中放置几个外星人。这次的实例创建不属于真实的外星人,不会编入aliens编组中。第二次创建alien实例在for循环内,即for循环遍历时,每次创建一个alien实例,并设置位置,再编入编组中。

aliens = Group(),是创建一个编组group的aliens的实例。同一文件中还有bullets的编组实例。注意Group()怎么用,是一个类的实例化。

4、重构create_fleet()

创建get_number_aliens_x()函数和create_alien()函数。将create_fleet()函数中的相关代码转移过去。

5、添加行

计算可以放置外星人的垂直空间,屏幕高度减去一个留白空间,一个外星人空间,一个间隔空间,一个飞船空间。

空间除以两倍外星人空间,为能够设置的行数。

为创建多行,我们使用两个嵌套循环,一个外部循环和一个内部循环,其中的内部循环创建一行外星人,而外部循环从0数到要创建的外星人行数。

注意:gf.create_fleet()函数一定要放在主程序while循环的外面,不然会重复的生成元素侵占内存。导致游戏无法正常运行。

13.4 让外星人群移动

1、向右移动外星人

在alien模块中创建update()方法。设置向右移动。移动速度因子在settings模块中进行确定。

在while循环中更新每个外星人的位置。先更新子弹,再更新外星人位置,后续要检查是否打掉外星人。

2、创建表示外星人移动方向的设置

在settings模块中创建self.fleet_drop_speed和self.fleet_direction。第一个设定向下移动的速度,第二个为移动方向,值为-1或者1,1代表右,-1代表左,很多情况会有这种操作。

3、检查外星人是否撞到了屏幕边缘

在alien模块中创建check_edge的方法,如果超出最右或超出最左,就返回True。

在alien模块中的update()方法中,位置移动乘以fleet_direction。这样如果调整方向直接从1变成-1,或者从-1变成1.

4、向下移动外星人群并改变移动方向

在game_function模块中进行修改。为什么在这里修改,不在alien模块中修改,为什么选择这个板块,搞不太懂。

编写check_fleet_edges()和change_fleet_direcion()方法。

change_fleet_direction方法中遍历整个外星人编组中的外星人向下移动,并改变方向。调用进check_fleet_edges()方法中。

check_fleet_edges()方法中遍历外星人编组中每个外星人,有存在符合check_edges()方法为True的,即运行change_fleet_direction。并且break跳出循环,后续的元素不再遍历,即只要编组中有一个被检查到碰到边缘,即整体舰队下移改变方向,后续是否还有其他触及边缘的不做检查。

13.5 射杀外星人

射杀外星人需要检测碰撞,即游戏元素重叠。将使用sprite.groupcollide()检测两个成员的碰撞。

1、检测子弹与外星人的碰撞

为实时知道是否发生碰撞,所以在子弹更新(bullet update)之后马上进行碰撞检测。

在gf模块中update_bullets()中新建collisions = pygame.sprite.groupcollide(bullets,aliens,True,True),实参解释如下:

groupcollide()遍历所有的bullets编组和aliens编组,即第一,第二实参。如果无碰撞,返回空字典,如果有碰撞,以第一实参的元素为键,第二实参的元素为值的键值对返回字典。第三个布尔值True为发生碰撞后删除相关键元素,第四个布尔值True为发生碰撞后删除相关值元素。

2、为测试创建大子弹

没什么内容,为测试不同的情况,修改一些参数,如修改子弹的大小,速度等测试外星人为空时的状态。

3、生成新的外星人群

在bullets_update里继续更新,如aliens为空,则bullets.empty()剩余的子弹,并且创建新的fleet。(但是感觉create_fleet()在bullets的函数里调用有点乱。)

4、提高子弹的速度

由于bullets_update()内容增加,pygame每次需要做很多工作,所以可能会影响子弹速度。(what??really??我感觉不应该啊。)

5、重构bullets_update()

简单重构,将检测bullets和aliens相撞的代码重构为一个函数。在bullets_update()中调用。

13.6 结束游戏

1、检测外星人和飞船碰撞

方法spritecollideany()接受两个实参:一个精灵和一个编组。它检查编组是否有成员与精灵发生了碰撞。并在找到与精灵发生碰撞的成员后就停止遍历编组。这里它遍历编组aliens,并返回它找到的第一个与飞船发生了碰撞的外星人,如果没有发生碰撞将返回一个none。 ---- 这个逻辑要清楚,这个方法的运行方式。

2、响应外星人和飞船碰撞

创建Gamestats类,保存在game_stats.py中。注意,这个类中的创建属性和方法。因为我们只创建一次Gamestats实例,但是每次游戏都要重置一下统计信息,所以重置信息放在reset_stats()方法中,而不在初始化中直接初始化。所以__init__()中的形参只有settings。而reset_stats()方法,因为在初始化中self.句点表达调用,所以它的方法下面的属性也用slef.句点生成,注意,没有在初始化方法中设置,而是在下面的方法中设置而且采用self.句点表达。

通过上述的表达方式,对于reset的设置,都可以在settings中进行配置,而只需要在GameStats类中实例化一次就可以。

在game_function中创建ship_hit的响应。ship_left减1,清空aliens,bullets,重新创建fleet,ship调整至底部中央,sleep一会儿。完成后在屏幕中刷新。

在ship模块中创建ship_center的方法,但是为什么这里要创建一个方法,不能直接做一个属性在ship_hit中调用呢?在整个游戏中,我们只创建了一个ship,并没有重新创建。

3、有外星人到达屏幕底端

注意break的位置。另外在ship_hit()中,ship.center_ship()中间有问题,为什么不能用self.rect.centerx,一定要用float之后的self.centerx。

4、游戏结束

设置一个游戏不运行的布尔值,当飞船小于1的时候,体现为false。后续用于游戏结束显示

13.7 确定应运行游戏的哪些部分

在主循环中任何时候都需要check_events,任何时候都需要刷新屏幕。这些是不以游戏是否运行为影响的,其他游戏内容可以用if条件进行选择运行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不贰笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值