回顾
我们在上一篇博客实现了添加特殊外星人,并且实现了大部分的功能,但是留了一部分,就是我们还没实现将统计过的大子弹进行实际的应用。
实现
回想一下我们当时为什么要创建四个外星人编组,因为我们在处理rect相交问题上,库函数的返回字典没有带上相交的对象。
所以我们没办法在一个编组中进行处理。同样,我们的大子弹也没法使用一个编组进行处理,而且大子弹的构建和事件处理本身就和正常子弹有不一样的地方,所以我选择新建一个类
上代码:
import pygame
from pygame.sprite import Spriteclass bullet_big(Sprite): #导入类是为了同时控制多个元素"""一个对发射的子弹进行管理的类"""def __init__(self,ai_settings,screen,ship):super(bullet_big,self).__init__()self.screen = screen#先在(0,0)创建一个子弹,然后再修改位置#因为子弹并非基于图像,所以就需要调用方法创建矩形self.rect = pygame.Rect(0,0,ai_settings.bullet_width_big,ai_settings.bullet_height)self.rect.centerx = ship.rect.centerxself.rect.top = ship.rect.top#小数格式的子弹位置self.y = float(self.rect.y)self.color = ai_settings.bullet_colorself.ship_speed_factor = ai_settings.bullet_speed_factordef update(self):"""向上移动子弹"""self.y -= self.ship_speed_factorself.rect.y = self.ydef draw_bullet(self):"""绘制子弹"""pygame.draw.rect(self.screen,self.color,self.rect)
基本上和原有的子弹相同,在子弹的规格(也就是创建的矩形框的大小)上进行了改变。
(规格都是在设置类中写死的部分)
在主文件alien_invasion.py中添加一个大子弹编组(bullets_big),就又到了我们愉快的修改事件函数的时间了。
看过上一次的都知道,添加了外星人编组后有多麻烦,但是确实没什么比较好的解决办法。
听说pygame.sprite.groupcollide函数其实还有最后一个参数,是控制返回值的,但是我没做了解,感兴趣的可以看一下。
修改事件函数
先整理一下子弹都参与了一些什么。
- 按下按键发射(这里选择的是b按键)
- 和外星人的碰撞事件
- 在升级或者损失一条命,以及需要重新开始的时候,清除操作
- 需要参与显示事件
发射子弹
对于按键事件,我们的处理函数为check_events,其中check_keydown_events是专门处理按下按键的操作。
在这里我添加了一个分支,调用发射大子弹的函数fire_bullet_big
elif event.key == pygame.K_b:fire_bullet_big(ai_settings,screen,ship,bullets_big,stats,sb)
函数:
def fire_bullet_big(ai_settings,screen,ship,bullets_big,stats,sb):if stats.big_bullet:#创建一颗子弹,加到编组中new_bullet = bullet_big(ai_settings,screen,ship)bullets_big.add(new_bullet)fire_music(ai_settings.bullet_music,stats)stats.big_bullet -= 1sb.prep_big_bullet()
如果还有大子弹的名额,就可以发射一枚大子弹,同时我们需要将统计类中的大子弹名额数减一,最后不要忘了调用记分牌的修改方法,否则屏幕显示会跟不上进度。
最后就是在这一系列的函数按层次添加参数即可。(层次是指按照函数调用的关系)
碰撞事件
自古碰撞最多事,上次的四个外星人编组差点把自己写自闭了。
上面说过了,我们库函数没法返回子弹是大子弹还是小子弹,而且我们的大子弹还是能连续碰撞外星人的,所以需要单独分开写。
我们选择的函数主体还是check_bullet_alien_collisions,上次我们添加了针对不同外星人的函数check_bullet_alien_collisions_part,这次我们又要对其进行魔改了。
这里我们也新建了一个函数:
def check_bullet_alien_collisions_big(ai_settings,screen,stats,sb,ship,aliens,bullets_big,different):collisions = pygame.sprite.groupcollide(bullets_big,aliens,False,True)if collisions:for alien in collisions.values():if different == "more":stats.score += ai_settings.alien_points * ai_settings.special_score_facteorelse:stats.score += ai_settings.alien_pointssb.prep_score()Sound = pygame.mixer.Sound(ai_settings.boom_music)Sound.set_volume(0.3)Sound.play()if different == "bullet":stats.big_bullet += 1sb.prep_big_bullet()
仍然是使用现成的库函数,对冲突的个体进行处理。这次我们将一个参数调为false,保证在检测到碰撞之后不会删除大子弹。
同时我们传入了一个判断外星人种类的字符串different,保证我们能对外星人的种类进行判断。
(我们对盾牌外星人也传入空字符串,使得盾牌外星人碰到子弹也会消失。)
判断冲突的函数在更新子弹的函数中被调用,这个函数接下来还需要修改。
重新开始
在外星人碰到了底部,或者是我们消出了所有的外星人,再或者是点击了play按钮,我们都需要将之前的所有子弹删除。
总结一下,有下述函数:
- ship_hit
- start_new_level
- check_play_button(之前外星人需要更新这事还忘了)
而这些函数又被一堆函数调用,还是疯狂套娃,这里就自己看看吧~
剩下的部分就是刷新,有:
- update_screen,需要渲染子弹
- update_bullets,需要更新子弹位置
这样,我们就实现了大子弹的功能。
结语
这是这个系列的最后一个魔改了,接下来我将给出将游戏整体打包成exe的方法,并且推出其他的py小游戏。
另外给一个提示,如果是使用蓝牙鼠标,在运行游戏的时候鼠标可能会失效,并且接收器会烫得一批,可能是影响了接触。
而且因为魔改的原因,游戏的运行还是会慢上一些,但确实没找到合适的修改方案(其实是懒得再折腾了,今天git差点把自己的提交记录整没了,还好GitHub还有自己的代码备份)