当前位置: 首页 > 后端技术 > Python

python-pygame实现飞机大战-3-发射子弹击中敌机

时间:2023-03-25 20:17:15 Python

完成玩家飞机移动,生成敌机以及两者的碰撞爆炸后,这一步只需要增加敌机发射的子弹和子弹打敌机功能:先上传图片,先准备好资源,也可以从网上下载。我这里直接用的教程的资源,为啥(确实很好看,自己找的就惨了)这次说说发射子弹的逻辑,对我来说很不容易。具体实现逻辑是四颗子弹连续循环,从而达到连续发射子弹的效果,但实际上只是四颗子弹来回移动。先放main.py,在上一步的代码中加入发射子弹、渲染子弹、子弹碰撞处理的模块子弹逻辑如下图所示。最后四个子弹不断循环importpygameimportsysimporttracebackfrompygame.localsimport*fromrandomimport*importmyplaneimportenemyimportbulletinitializepygame.init()setwindowsizebg_size=width,height=400,700#其实就是一个元组screen=pygame.display.set_mode(bg_size)#设置窗口pygame.display.set_caption("PlaneWars")#窗口标题加载背景图片,对于普通图片的显示效果有没有convert都一样,只是使用convert可以转换格式,提高blit的速度background=pygame.image.load("images/background.png").convert()设置黑色,绿色,红色,几百种颜色对应的值,BLACK=(0,0,0)GREEN=(0,255,0)RED=(255,0,0)WHITE=(255,255,255)稍后将用于生成敌方小型飞机defadd_small_enemy(small_enemies,enemiesGroup,num):foriinrange(num):smallenemy=enemy.SmallEnemy(bg_size)#elf组用于实现多图,非常适合处理精灵列表,有添加、删除、绘制、更新等方法。#Group.sprites精灵组#group.copy复制#group.add添加#group.remove移除#group.has判断精灵组成员#group.update更新#group.draw位块显示#group.clear-绘制背景#group.empty清除#将这组敌机添加到小飞机属性中,相当于统一处理统一赋值small_enemies.add(smallenemy)enemiesGroup.add(smallenemy)defmain():#创建时钟对象(可以控制游戏循环频率)clock=pygame.time.Clock()#生成玩家飞机me=myplane.MyPlane(bg_size)#存储所有敌机,这个飞机组包含小型飞机、中型飞机和大型飞机的各种属性,只要用到用于处理Collision#当程序中存在大量实体时,操作这些实体会相当麻烦#使用pygame.sprite.Group()函数创建精灵组统一管理。这里创建了一个敌人组enemiesGroup=pygame.sprite.Group()#生成局部小飞机,敌人小飞机也是一个组,一起处理small_enemies=pygame.sprite.Group()add_small_enemy(small_enemies,enemiesGroup,15)#生成普通子弹,这里是四发子弹循环bullet1s=[]#标记是哪个子弹发生了bullet1s_index=0#子弹数量bullet1_num=4foriinrange(bullet1_num):#将玩家飞机的位置发送给子弹classbullet1s.append(bullet.Bullet1(me.rect.midtop))#标记是否使用超级子弹is_double_bullet=False#玩家三命life_num=3#设置无敌时间事件,pygame.USEREVENT代表事件1,pygame.USEREVENT+1代表事件2,以此类推,这里相当定义一个Eventinvincible_event=pygame.USEREVENT#游戏暂停,默认为非暂停状态paused=False#控制玩家飞行器图像切换,显示突如其来的效果switch_image=True#切换延迟delay=100#游戏得分score=0#Theplaneexploded图片下标分别为小型敌机、中型敌机、大型敌机的下标,以及玩家机的爆炸图。切换下标改变爆炸图e1_destory_index=0e2_destory_index=0e3_destory_index=0me_destory_index=0running=Truewhilerunning:#GetEventforeventinpygame.event.get():#结束事件触发结束操作ifevent.type==QUIT:pygame.quit()sys.exit()#writepygame.time.set_timerwhencollisionistriggered(invincible_event,3*1000)#表示invincible_event事件会在3秒后执行。invincible_event事件在此处捕获。执行完后会取消定时器,防止循环重复执行,等待下一次触发ifevent.type==invincible_event:#解除无敌状态me.invincible=Falsepygame.time.set_timer(invincible_event,0)#检测用户键盘操作,分别为_pressed[K_a]orkey_pressed[K_LEFT]:me.moveLeft()ifkey_pressed[K_d]orkey_pressed[K_RIGHT]:me.moveRight()#在屏幕上绘制背景图并指定位置screen.blit(background,(0,0))#画子弹补给,炸弹补给等各种元素#不暂停,暂停life大于0==Falseandlife_num>0:#画小敌机,这里是因为小飞机上面定义了group,aircraftgroup添加了小飞机属性(速度,位置等),此时在地图上生成了飞机#如果这些飞机属于小型敌方飞机,会在small_enemies中为ei一起处理:#敌机还活着,没有被摧毁ifei.active==True:#绘制小敌机,敌机开始移动screen.blit(ei.image,ei.rect)ei.samll_enemy_move()#小敌机被摧毁(被玩家摧毁或与玩家相撞)else:#Settingdelay%4here意思是爆炸画面是4帧(个人猜测),理解为爆炸持续时间,如果不是可以自己设置(delay%4):#用来播放爆炸音效,每个敌机只播放一次ife1_destory_index==0:print("播放敌机爆炸声")#绘制敌机撞击爆炸声screen.blit(ei.destory_images[e1_destory_index],ei.rect)#切换爆炸图下标,从而切换爆炸图Explosion#这里选择重新生成ife1_destory_index==0:ei.reset()score+=1000print("Score:",score)#做碰撞detection,pygame.sprite.spritecollide(sprite,sprite_group,bool):a组中的所有精灵都会对另一个单个精灵逐一进行冲突检测,冲突的精灵会以列表的形式返回#第一个参数是单个sprite,第二个参数是精灵组,第三个参数是bool值,最后一个参数起到了很大的作用。为True时,组内所有冲突的精灵都会被删除,为False时,冲突的精灵不会被删除#第四个参数为:两个精灵之间的像素遮罩检测enemy_collide=pygame.sprite.spritecollide(me,enemiesGroup,False,pygame.sprite.collide_mask)#碰撞处理,如果enemy_collide而不是me.invincible:#玩家飞机触发破坏状态me.active=False#enemy_collide是一个列表,存储了所有与玩家飞机相撞的敌机,然后将碰撞敌机的状态设置为destroyed状态foreiinenemy_collide:ei.active=False#绘制玩家飞机,如果飞机是活动的ifme.active:#在屏幕上绘制玩家飞机Airplane,switch_image是否切换图片ifswitch_image:screen.blit(me.image1,me.rect)#切换飞行图片else:screen.blit(me.image2,me.rect)#表示飞机相撞了爆炸被激活Eventelse:ifnot(delay%4):#用来播放爆炸声,每个敌机只播放一次ifme_destory_index==0:print("Playerplaneexplosionsound")#绘制玩家撞击爆炸画面screen.blit(me.destory_image[me_destory_index],me.rect)#切换爆炸图的下标,从而切换爆炸图me_destory_index=(me_destory_index+1)%4#爆炸图播放后,飞机重生ifme_destory_index==0:#一个生命会减少,如果看到0,会自动跳过上一个循环life_num-=1#重置状态me.reset()#无敌时间设置为3秒,3秒后触发无敌时间事件,pygame.time.set_timer:每隔一段时间(这里是3毫秒*1000=3s),执行一些动作pygame.time.set_timer(invincible_event,3*1000)#每10个单位时间发射一颗子弹ifnot(delay%10):#如果是普通子弹ifis_double_bullet==False:bullets=bullet1s#先固定子弹0的位置bullets[bullet1s_index].reset(me.rect.midtop)#切换到下一颗子弹bullet1s_index=(bullet1s_index+1)%bullet1_num#在bullets中为bull绘制子弹:ifbul.active:#如果子弹是活动的,它可以移动和绘制bul.move()screen.blit(bul.image,bul.rect)#子弹与敌机的碰撞,子弹与敌群的碰撞,一般情况下其实是1对1的碰撞enemy_hit=pygame.sprite.spritecollide(bul,enemysGroup,False,pygame.sprite.collide_mask)#如果有敌机被子弹击中ifenemy_hit:#击中敌机的子弹首先被标记为非活动状态,当它实际上被重置时子弹下一次击中子弹。会再次显示bul.active=Falseforeiinenemy_hit:ei.active=Falsedelay-=1ifdelay==0:delay=100#每5帧切换飞行图像样式ifdelay%5==0:switch_image=notswitch_image#更新整个Surface对象显示在屏幕上,将内存中的内容显示在屏幕上pygame.display.flip()#通过时钟对象指定循环频率,60个循环/秒#的帧率是指程序每秒在屏幕上画一张图clock.tick(60)ifname=="__main__":try:main()#服务正常退出exceptSystemExit:print("游戏正常退出!")#pass忽略错误继续运行,其实这里就是退出pass#服务中出现的其他异常除外:#直接把错误打印出来traceback.print_exc()pygame.quit()bullet.py:主要是控制的子弹,包括子弹的各种属性,以及子弹的重置知识重点和敌机的步骤类似,主要是逻辑,其他的加的不多子弹也改了def__init__(self,position):#这里还是一样,“基类初始化”,看介绍在enemy.py中获取详细信息pygame.sprite.Sprite.__init__(self)self.image=pygame.image.load('images/bullet1.png').convert_alpha()#get_rect()是处理矩形图片的方法,返回值包含矩形的属性,这里返回飞机图片1的位置,可以得到图片的宽高属性self.rect=self.image.get_rect()#定义子弹的位置self.rect.left=position[0]self.rect.top=position[1]#判断子弹是否激活self.active=True#子弹速度self.bulletSpeed=12#碰撞检测会忽略图片的白色背景部分self.mask=pygame.mask.from_surface(self.image)#子弹运动defmove(self):self.rect.top-=self.bulletSpeed#超出屏幕,定义为inactive状态,同时kill掉,否则耗资源ifself.rect.top<0:self.active=False#Bulletresetdefreset(self,position):self.active=Trueself.rect.left=position[0]self.rect.top=position[1]myplane.py:主要是p的控制layer的飞机,包括[游戏](http://www.cungun.com/)飞机的各种属性,飞机的上下左右移动飞行器的移动和重生enemy.py(敌机类,包括敌机的属性、操作、重置等)这里就不放了。前面的步骤都到了这一步。这一步的作用是控制飞行器的运动。射击并摧毁敌机