pygame-飞机大战(下·二)

动画类在https://blog.csdn.net/qq_36614557/article/details/91409885介绍。

一、Kinds文件夹

    Kinds文件夹下定义了多个本机、敌机、子弹等单位类,每个类自成一个py文件,并以类名命名。

   1.Ship类

    Ship类除了定义了基本的初始化和刷新以外,还包括:

    (1) update_revive函数,在刷新函数中被调用,用来显示复活界面,函数内直接使用Animation,并通过while循环计数来进行复活等待。

    (2) active_animation函数,用来在进入新关卡时,显示关卡的进入动画(和游戏同时进行)。

    (3) update_animation函数,用来刷新动画组。

    (4) handleInit函数,调用Handle类的对象,在事件触发器添加键盘按钮和触发函数(事件)字典项。

    (5) hit函数,空格键的触发函数,调用当前关卡的hit()函数,射出子弹。

    (6) left/right/up/down_button,adwd键的触发函数,改变当前飞机是否朝某个方向前行的状态,该状态在Ship的初始化里,长按可实现连续朝某个方向前进。

    (7) quitui函数,q键的触发函数,改变当前的状态,即game_active置False,ui_active置True,用来实现退出游戏,范围至主菜单界面。

    (8) pause函数,p键的触发函数,改变当前的状态,暂停游戏打开商店或退出商店继续游戏。如果要打开商店,在此随机出现一个参数用来随机出现某限定道具。

    (9) change函数,o键的触发函数,改变当前的状态,进入飞机颜色设计界面或退出界面并继续之前的页面。

    (10) use函数,e键的触发函数,如果是第一关/第三关,则使用当前持有的道具,如果是第二关,则随机释放道具。

    (11) random_reset函数,随机传送飞机至一定区域内任意位置[第四章 随机事件内]。

    (12) drawachi函数,draw中调用,在屏幕右上角绘制“获得成就”以及对应的成就名和获得方式。

    (13) reset函数,r键的触发函数,清除异常事件(HI.clear())并重置至指定位置。

    (14) position_reset函数,血量恢复至100【第三章/第四章】,并并重置至指定位置。【复活后触发】

    (15) drawBlood函数,通过使用pygame.draw.line函数在飞机头顶上画血条并随着飞机位置变化而变化【第三章/第四章】

    (16) draw_background函数,根据当前的关卡数绘制关卡背景。

    (17) boom_load函数,显示加载条,如果满了就提示可以按E释放。【第二章】

    (18) draw_life/draw_bullet/draw_score函数,根据当前剩余生命值/子弹数/积分值/持有道具/道具进度条等在屏幕上端绘制出来。

    (19) standardlize,类外函数,对输入的数字转化到K/M/G级别返回字符串。

初始化函数init()中包括贴图等的加载、状态的声明、数值的初始化等。

更新函数update()包括根据状态进行更新位置等。

绘制函数draw()包括以上各种绘制函数。

import pygame
import time
import random
from Codes.Base.Screen import SI
from Codes.Logic.GameStates import GStI
from Codes.Common.DrawBase import DrawOn,DCI
from Codes.Base.GameSettings import GSeI
from Codes.Input.Handle import HI
from Codes.Battles.Battle1 import BI as Battle1
from Codes.Battles.Battle2 import BI as Battle2
from Codes.Battles.Battle3 import BI as Battle3
from Codes.Battles.Battle4 import BI as Battle4
from Codes.Base.Animation import Animation
def returnbattle():
    Battles=[Battle1,Battle2,Battle3,Battle4]
    return Battles[GStI.current_checkpoint-1]
class Ship(DrawOn):
    def __init__(self):
        super().__init__()
        super(Ship,self).definePriority(2)

    def init(self):
        self.ship_speed_factor=GSeI.ship_speed_factor*2
        (w,h)=(GSeI.ship_width,GSeI.ship_height)
        self.image_list=[]
        self.image2_list=[]
        for i in range(18):
            filename='images/Ship/plane_'+str(i)+'_'
            img=pygame.image.load(filename+'1.png').convert_alpha()
            self.image_list.append(pygame.transform.scale(img,(w,h)))
            img2=pygame.image.load(filename+'2.png').convert_alpha()
            self.image2_list.append(pygame.transform.scale(img2,(w,h)))
        cs=GSeI.color_select
        self.image=self.image_list[cs]
        self.image_wudi = pygame.image.load('images/Ship/plane_wudi_1.png').convert_alpha()
        self.image2_wudi = pygame.image.load('images/Ship/plane_wudi_2.png').convert_alpha()
        self.image_wudi = pygame.transform.scale(self.image_wudi,(w,h))
        self.image2_wudi = pygame.transform.scale(self.image2_wudi,(w,h))
        self.img_mini=pygame.transform.scale(self.image,(40,40))
        self.bullet_mini=pygame.image.load('images/bullet_shotgun.png').convert_alpha()
        self.bullet_mini=pygame.transform.scale(self.bullet_mini,(12,40))
        self.image_achi=pygame.image.load('images/achi.jpg').convert_alpha()
        self.image_achi=pygame.transform.scale(self.image_achi,(292,50))
        self.rect = self.image.get_rect()
        self.screen=SI.screen
        self.screen_rect = SI.screen.get_rect()
        self.rect.centerx = self.screen_rect.centerx
        self.rect.centery = self.screen_rect.centery
        self.rect.bottom = self.screen_rect.bottom
        self.pos_x=float(self.rect.centerx)
        self.pos_y=float(self.rect.centery)
        self.moving_right=False
        self.moving_left=False
        self.moving_up=False
        self.moving_down=False
        self.handleInit()
        self.chapter=[1]*4
        self.j=1
        self.info=[]
        self.framerate = pygame.time.Clock()
        self.framerate.tick(30)
        self.group =pygame.sprite.Group()
        self.boom=0
        self.delay=20#boom_load的文字显示时延
        self.image_chapter=[]
        for i in range(4):
            temp=pygame.image.load('images/bg_chapter_'+str(i+1)+'.jpg')
            temp = pygame.transform.scale(temp,(1200,800))
            self.image_chapter.append(temp)
    
    def update(self,delta):
        checkpoint=GStI.current_checkpoint-1
        if self.chapter[checkpoint]==1:
            self.active_animation(checkpoint)
        if GStI.revive==True: 
            self.update_revive()
        v_add=GSeI.sou*(7-GSeI.sou)*10
        updown=1
        if GSeI.updown>0:
            updown=-1
        if GSeI.shufu<=0:
            if self.moving_right  and self.rect.right <  GSeI.screen_width:
                self.pos_x +=  (self.ship_speed_factor+v_add)*delta*updown
            if self.moving_left and self.rect.left > 0:
                self.pos_x -=  (self.ship_speed_factor+v_add)*delta*updown
            if self.moving_down  and self.rect.bottom < GSeI.screen_height:
                self.pos_y +=  (self.ship_speed_factor+v_add)*delta*updown
            if self.moving_up and self.rect.top > 0:
                self.pos_y -=  (self.ship_speed_factor+v_add)*delta*updown
        self.rect.centerx=self.pos_x
        self.rect.centery=self.pos_y
        self.preDraw()

    def update_revive(self):
        self.revive=1
        self.animation_scroll= Animation(self.screen,400,400)
        self.animation_scroll.load("images\scroll\scroll.png", 415, 224, 4)
        self.group.add(self.animation_scroll)
        while self.revive<=3000:
            ticks = pygame.time.get_ticks()
            self.group.update(ticks)
            self.group.draw(self.screen)
            pygame.display.update()
            self.revive=self.revive+1 
        GStI.revive=False
        self.group.remove()
        
    def active_animation(self,i):
        self.animation = Animation(self.screen,0,250)
        self.animation.load("images\chapter\chapter0"+str(i+1)+".png", 1200, 240, 6)
        self.group.add(self.animation)
        
    def update_animation(self,i):
        if self.chapter[i]<=60:
            ticks = pygame.time.get_ticks()
            self.group.update(ticks)
            self.group.draw(self.screen)
            pygame.display.update()
            self.chapter[i]=self.chapter[i]+1 
        if self.chapter[i]>60:
            self.chapter[i]=0
            self.group.empty()
        
    def handleInit(self): 
        HI.add(pygame.K_a,self.left_Button)
        HI.add(pygame.K_w,self.up_Button)
        HI.add(pygame.K_s,self.down_Button)
        HI.add(pygame.K_d,self.right_Button)
        HI.add(pygame.K_p,self.pause)
        HI.add(pygame.K_o,self.change)
        HI.add(pygame.K_q,self.quitui) 
        HI.add(pygame.K_e,self.use)
        HI.add(pygame.K_r,self.reset)
        HI.add(pygame.K_SPACE,self.hit)
        
        
    def hit(self):
        BI=returnbattle()
        if GStI.current_checkpoint<4:
            BI.hit()

    def left_Button(self):
        self.moving_left=self.moving_left^1


    def right_Button(self):
        self.moving_right=self.moving_right^1

    def up_Button(self):
        self.moving_up=self.moving_up^1

    def down_Button(self):
        self.moving_down=self.moving_down^1

    def quitui(self):
        if  GStI.game_active==True:
            GStI.ui=True
            GStI.game_active=False
        
    def pause(self):
        if GStI.current_checkpoint==1 or GStI.current_checkpoint==3:              
            if GStI.change_active==False and GStI.game_active==True:
                GStI.game_active=False
                GStI.store_active=True
                tool=['至尊VIP','永久加成卡','清屏','屏障','超级加倍卡']
                length=len(tool)-GSeI.vip-GSeI.pac
                item=random.randint(0,length-1)
                if length==len(tool)-2:
                    item+=2
                elif length==len(tool)-1 and GSeI.vip==1:
                    item+=1
                elif length==len(tool)-1 and GSeI.vip==0:
                    if item!=0:
                        item+=1
                GSeI.item=item
            elif GStI.store_active==True:
                GStI.game_active=True
                GStI.store_active=False
                
    def change(self):      
        if GStI.game_active==True and GStI.store_active==False:
            GStI.game_active=False
            GStI.change_active=True
        elif GStI.change_active==True:
            GStI.game_active=True
            GStI.change_active=False        

    def use(self):
        BI=returnbattle()
        if GStI.current_checkpoint==2:
            if self.boom >= 100:                      
                r = random.choice([1,2])
                if r==1:   
                    BI.boom()
                if r==2:                                    
                    BI.addbullet_s1()
                self.boom = 0;    
        elif GStI.current_checkpoint!=4:
            if GStI.game_active==True:
                if GSeI.use==1:
                    BI.clear_aliens()
                if GSeI.use==2:
                    GStI.wudi=True
                    GSeI.wudi_left=GSeI.wudi_time
                if GSeI.use==3:
                    GStI.tac=True
                    GSeI.tac_left=GSeI.tac_time
                if GSeI.use==4:
                    GSeI.ding=3
                if GSeI.use==5:
                    GSeI.sou=7
                if GSeI.use==6:
                    GSeI.xuruo=5
                GSeI.use=0
                
    def random_reset(self):
        self.rect.centerx=random.randint(50,1150)
        self.pos_x=self.rect.centerx
        self.rect.centery=random.randint(50,750)
        self.pos_y=self.rect.centery
        self.moving_right=False
        self.moving_left=False
        self.moving_up=False
        self.moving_down=False       
       
    def center_ship(self):
        self.center=self.screen_rect.centerx
        
    def preDraw(self):
        DCI.add(self)
        
    def draw(self):
        self.draw_background()
        self.print_information()
        self.draw_life()
        if GStI.current_checkpoint!=4:
            self.draw_bullet()
        cs=GSeI.color_select
        if GStI.wudi==False:
            if time.time()%1>0.5:
                self.screen.blit(self.image_list[cs], self.rect)
            else:
                self.screen.blit(self.image2_list[cs], self.rect)
        else:
            if time.time()%1>0.5:
                self.screen.blit(self.image_wudi, self.rect)
            else:
                self.screen.blit(self.image2_wudi, self.rect)
    
        if GStI.current_checkpoint>=3:
            self.drawBlood()   
        self.draw_score()
        if GStI.current_checkpoint==2:
            self.boom_load()
        for i in range(16):
            if GSeI.achi_active[i]==1: #如果某个成就动态开启 则调用函数
                if self.j<60: #循环60帧
                    self.drawachi(i)
                    self.j+=1
                else:
                    self.j=1
                    GSeI.achi_active[i]=0
        checkpoint=GStI.current_checkpoint-1
        if self.chapter[checkpoint]!=0:
            self.update_animation(checkpoint)

    def drawachi(self,i):#绘制获得第i个成就
        self.screen.blit(self.image_achi,(800,0,292,50))
        self.print_text('获得成就:'+GSeI.achiname[i],880,25,rgb=(255,0,0),textsize=18)
        self.print_text(GSeI.achitext[i],900,43,rgb=(0,255,255),textsize=15)       

    def reset(self):
        self.rect.centerx=GSeI.screen_width*0.5
        self.pos_x=self.rect.centerx
        self.rect.centery=GSeI.screen_height*0.8
        self.pos_y=self.rect.centery
        HI.clear()
        self.handleInit()
        self.moving_right=False
        self.moving_left=False
        self.moving_up=False
        self.moving_down=False 
        
    def position_reset(self):
        self.rect.centerx=GSeI.screen_width*0.5
        self.pos_x=self.rect.centerx
        self.rect.centery=GSeI.screen_height*0.8
        self.pos_y=self.rect.centery
        self.moving_right=False
        self.moving_left=False
        self.moving_up=False
        self.moving_down=False 
        self.blood=100
        
    def drawBlood(self):
        if self.blood>=0:
            blood=self.blood/100
            if blood >=0.3:
                blood_color=[0,255,0]
            else:
                blood_color=[255,0,0]
            pygame.draw.line(self.screen,[0,0,0],(self.rect.left,self.rect.top-5),(self.rect.right,self.rect.top-5),3)
            pygame.draw.line(self.screen,blood_color,(self.rect.left,self.rect.top-5),(self.rect.left+self.rect.width*blood,self.rect.top-5),3)

  
    def draw_background(self):
        if not GStI.ui and not GStI.die_active and not GStI.background:
            point=GStI.current_checkpoint
            self.screen.blit(self.image_chapter[point-1],self.image_chapter[point-1].get_rect())
    def boom_load(self):
        pygame.draw.rect(self.screen,[0,206,206],(20,160,105,10),3)
        if self.boom < 100:
            self.boom += 0.2
        pygame.draw.line(self.screen,[241,88,88],(22,164),(22+self.boom,164),6)
        

            
        font = pygame.font.Font("fonts/Amadeus.ttf",30)
        text = font.render("(Press ’E‘ to use)",True,(0,206,206))
        if self.boom >= 100:
            if self.delay  <= 0:
                self.screen.blit(text,(220,70))
            self.delay -= 1
            if self.delay == -20:
                self.delay = 20;
                
    def draw_life(self):
        life=GStI.ships_left
        font = pygame.font.Font("fonts/TianGeKaiTi.TTF",30)
        text = font.render("生命:",True,(0,206,206))
        self.screen.blit(text,(20,55))
        i=0
        while i<=life:
            self.screen.blit(self.img_mini,(100+40*i,60,40,40))
            i+=1

    
    def draw_bullet(self):
        BI=returnbattle()
        font = pygame.font.Font("fonts/TianGeKaiTi.TTF",30)
        if  GSeI.weapon!=1:#激光枪显示时间,其他显示剩余子弹数量
            number= GSeI.bullets_allowed-len(BI.bullets)     
            text = font.render("子弹:",True,(0,206,206))
            self.screen.blit(text,(20,100))
            i=0
            while i<=number:
                self.screen.blit(self.bullet_mini,(150+15*i,100,12,40))
                i+=1
        else:#如果是激光枪,则显示剩余时间/充能时间
            text=''
            pygame.draw.rect(self.screen,[0,206,206],(130,116,105,10),3)
            if GStI.shotgun_active==False:#如果武器未打开,则显示剩余充能时间 
                prop=100-GSeI.charge_left/GSeI.charge_time*100
                text = font.render("Charge:",True,(10,240,10))
                pygame.draw.line(self.screen,[10,240,20],(132,120),(132+prop,120),6)
            else:
                prop=GSeI.left_time/GSeI.max_time*100
                text = font.render("Release:",True,(0,206,206))
                pygame.draw.line(self.screen,[240,120,88],(132,120),(132+prop,120),6)
            self.screen.blit(text,(20,100))
        
    def draw_score(self):#显示积分 金币 道具
        BI=returnbattle()
        font = pygame.font.Font("fonts/TianGeKaiTi.TTF",30)
        text=font.render("积分:"+standardlize(BI.score),True,(0,206,206))    
        self.screen.blit(text,(20,20))

        if GStI.current_checkpoint==4:
            if BI.gold==0:#显示子弹数量和 时间  
                text=font.render("时间:"+str(int(BI.time))+'s',True,(0,206,0))    
                self.screen.blit(text,(170,20))
            else: 
                
                text=font.render("金币转化为积分中",True,(random.randint(0,255),random.randint(0,255),random.randint(0,255)))    
                self.screen.blit(text,(300,20))
        else:
            text=font.render("金币:"+standardlize(BI.gold),True,(255,215,0))    
            self.screen.blit(text,(170,20))
        if GStI.current_checkpoint%2==1:
            tool=['无','清屏','屏障','超级加倍卡','中娅沙漏','幽灵疾步','虚弱']
            text=font.render("道具:"+tool[GSeI.use],True,(0,110,255))   
            self.screen.blit(text,(20,160))
        text=[]
        prop=[]
        if GSeI.ding>0:
            text.append('金身:')
            prop.append(GSeI.ding/3*100)
        if GSeI.sou>0:
            text.append('疾步:')
            prop.append(GSeI.sou/7*100)
        if GStI.wudi==True:#如果处在无敌状态 则同时显示还有多少时间  
            text.append("无敌:")
            prop.append(GSeI.wudi_left/10*100)
        if GSeI.xuruo>0:
            text.append('虚弱:')
            prop.append(GSeI.xuruo/5*100)
        if GSeI.shufu>0:
            text.append('束缚:')
            prop.append(GSeI.shufu/3*100)
        if GSeI.updown>0:
            text.append('颠倒:')
            prop.append(GSeI.updown/10*100)
        index=0
        while index<len(prop):
            t=font.render(text[index],True,(240,110,110))   
            self.screen.blit(t,(20,240+40*index))
            pygame.draw.rect(self.screen,[0,206,206],(100,250+40*index,105,10),3)
            pygame.draw.line(self.screen,[10,240,20],(100,254+40*index),(100+prop[index],254+40*index),6)
            index+=1
            
    def print_text(self,text,pos_x,pos_y,rgb=(0,255,255),texttype='kaiti',textsize=16):#缺省参数的显示文字
        font1 = pygame.font.SysFont(texttype, textsize)
        textSurfaceObj = font1.render(text, True, rgb)
        textRectObj = textSurfaceObj.get_rect()
        textRectObj.bottomleft=(pos_x,pos_y)
        self.screen.blit(textSurfaceObj, textRectObj)
    
    
    def print_information(self):#显示左下角信息
        len_info=len(self.info)
        while len_info>=1 and len_info>=len(self.info)-15:#最多显示15条
            self.print_text(self.info[len_info-1],50,730-20*(len(self.info)-len_info),rgb=(255,255,255),texttype='fangsong',textsize=14)
            len_info-=1

def standardlize(num):
    if num>=pow(10,9):
        num=round(num/pow(10,9),1)
        return str(num)+'g'
    elif num>=pow(10,6):
        num=round(num/pow(10,6),1)
        return str(num)+'m'
    elif num>=pow(10,3):
        num=round(num/pow(10,3),1)
        return str(num)+'k'
    else:
        return str(round(num))
  

2.普通敌机类Aliens.py:

第一章/第二章/第三章常见的地方单位,结构简单。

第一、二章中碰到本机子弹就死亡,第三章中拥有血条且发射子弹。发射子弹通过元素time控制,并在Battle内发射。check_edges函数返回这个单位是否越界。在初始化函数中会随机敌机的位置、方向、速度等,并在刷新函数中根据速度等更新位置。

import pygame
import random
import math
from pygame.sprite import Sprite
from Codes.Base.GameSettings import GSeI
from Codes.Logic.GameStates import GStI
from Codes.Base.Screen import SI
from Codes.Common.DrawBase import DrawOn,DCI


class Alien(Sprite,DrawOn):
    def __init__(self):
        super(Alien, self).__init__()
        super(Alien,self).definePriority(3)
        self.priority=3
        self.screen=SI.screen
        self.image_ = pygame.image.load('images/alien.png').convert_alpha()
        self.image_ = pygame.transform.scale(self.image_,(int(GSeI.aliens_size),int(GSeI.aliens_size)))
        self.rect = self.image_.get_rect()
        self.dir=random.randint(30,150)#运动的偏转角度 取值为30度到150度
        self.theta=self.dir*math.pi/180#转为弧度制 便于计算
        self.image=pygame.transform.rotate(self.image_, 90-self.dir)
        self.v=random.uniform(GSeI.aliens_v_min,GSeI.aliens_v_max)#初始速度
        self.a=random.uniform(1,1.01)#加速度
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height
        self.rect.center=(random.randint(20,GSeI.screen_width-20),30)#随机生成点的位置
        self.blood=50
        self.x = float( self.rect.x )
        self.y = float( self.rect.y )
        self.time=0 #生存时间 每次update+1  每%4为1时候 发射子弹 

    def draw(self):
        self.screen.blit(self.image, self.rect)
        if GStI.current_checkpoint==3:
            self.drawBlood()
            
    def drawBlood(self):
        if self.blood>=0:
            blood=self.blood/50
            if blood >=0.3:
                blood_color=[0,255,0]
            else:
                blood_color=[255,0,0]
            pygame.draw.line(self.screen,[0,0,0],(self.rect.left,self.rect.top-5),(self.rect.right,self.rect.top-5),3)
            pygame.draw.line(self.screen,blood_color,(self.rect.left,self.rect.top-5),(self.rect.left+self.rect.width*blood,self.rect.top-5),3)
    def preDraw(self):
        DCI.add(self)

    def update(self,delta):
        if GSeI.ding<=0:
            self.x+=math.cos(self.theta)*self.v
            self.y+=math.sin(self.theta)*self.v
        self.v*=self.a
        self.rect.x =self.x
        self.rect.y=self.y
        self.rect.center=(self.x,self.y)
        self.time+=1
        if GStI.current_checkpoint==2:
            if self.rect.left <= 0 or self.rect.right >= 1200:   #碰壁之后掉头
                self.kill()

        self.preDraw()
        

    def check_edges(self):
        screen_rect =SI.screen.get_rect()
        if self.rect.right >= screen_rect.right:
            return True
        elif self.rect.left <=0:
            return True

3.普通子弹类Bullets:

为了节省时间,本机的普通子弹和敌机(不包括BOSS)发射的子弹使用同一类,通过初始化的输入参数hostkind控制,更新函数同理。通过判断hostkind的值来区分本机子弹和敌机子弹。

import pygame
import math
from pygame.sprite import Sprite
from Codes.Base.GameSettings import GSeI
from Codes.Common.DrawBase import DrawOn,DCI
from Codes.Base.Screen import SI

class Bullet(Sprite,DrawOn):

    def __init__(self):
        super(Bullet, self).__init__()
        super(Bullet,self).definePriority(3)

    def init(self,host,theta,hostkind):#hostkind=1 机主子弹 hostkind=0 敌机 
        self.screen = SI.screen
        
        if hostkind==1:
            self.image = pygame.image.load('images/ship_bullet.png').convert_alpha()
            self.image = pygame.transform.scale(self.image,\
            (int(GSeI.bullet_width),int(GSeI.bullet_height)))
            self.speed_factor = GSeI.bullet_speed_factor
        else:
            self.image = pygame.image.load('images/bullet.png').convert_alpha()
            self.image = pygame.transform.scale(self.image,\
            (int(GSeI.alien_bullet_width),int(GSeI.alien_bullet_height)))
            self.speed_factor =GSeI.alien_bullet_speed
            
        self.image=pygame.transform.rotate(self.image, 90-theta)
        self.rect = self.image.get_rect()
        self.rect.centerx = host.rect.centerx
        self.rect.top = host.rect.top
        self.y = float(self.rect.y)
        self.x = float(self.rect.x)
        self.theta=theta*math.pi/180

    def update(self,delta,host):#host=1 机主 host=0 敌机
        if host==1 or GSeI.ding<=0:
            self.y-=self.speed_factor*delta*math.sin(self.theta)
            self.x-=self.speed_factor*delta*math.cos(self.theta)   
        self.rect.y=self.y
        self.rect.x=self.x
        self.preDraw();

    def preDraw(self):
        DCI.add(self)
    def draw(self):
        self.screen.blit(self.image, self.rect)



在之后的设计开发阶段里,加入了大量的其他类,如BOSS、BOSS子弹、超级子弹、Bonus、陨石、流星、敌机阵列、Bonus组、三种新型武器、三种敌对子弹等,设计理念与以上三类大同小异,因此不在此过多介绍,贴出其中部分代码:

Alien_Boss.py:

第二章敌对单位BOSS,拥有血量,会发射大量子弹。

import pygame
from Codes.Kinds.Boss_Bullet import Boss_Bullet
from Codes.Common.DrawBase import DrawOn,DCI
from Codes.Base.Screen import SI
from Codes.Base.GameSettings import GSeI

class Alien_Boss(pygame.sprite.Sprite,DrawOn):   
    
    def __init__(self):
         super(Alien_Boss,self).__init__()
         super(Alien_Boss,self).definePriority(3)
         self.screen=SI.screen
         image = pygame.image.load("images/alien.png").convert_alpha()
         rect = image.get_rect()
         self.image = pygame.transform.scale(image,(int(rect.width * 0.2),\
                                    int(rect.height * 0.2)))
         self.rect = self.image.get_rect()
         self.blood = 50
         self.active = True
         self.rect.bottom = 0 - self.rect.height
         self.rect.left = (1200 - self.rect.width) // 2 
         self.mask = pygame.mask.from_surface(self.image)
         self.speed = 3
         self.bullets = pygame.sprite.Group()
         self.bg_size =[GSeI.screen_width,GSeI.screen_height]
         self.go_down=True
         
    def update(self):
         if self.rect.top <=30:
             self.go_down=True
         if self.rect.top>=100:
             self.go_down=False
         if self.rect.top <= 30:
             self.rect.top += abs(self.speed)
         else:
             if self.go_down:
                 self.rect.top += abs(self.speed)
             else:
                 self.rect.top -= abs(self.speed)
                 
             if self.rect.right >= self.bg_size[0] or self.rect.left <= 0:
                 self.speed = -self.speed
             self.rect.left += self.speed     #BOSS先下落到一定距离,之后在一直左右移动
         self.preDraw()
                 
    def drawBlood(self,screen):
         if self.blood >= 0:
             blood = self.blood / 50
             if blood > 0.3:
                 blood_color = [0,255,0]
             else:
                 blood_color = [255,0,0]
             pygame.draw.line(screen,[0,0,0],(self.rect.left,self.rect.top -5),
                                         (self.rect.right,self.rect.top - 5),3)
             pygame.draw.line(screen,blood_color,(self.rect.left,self.rect.top -5),\
                (self.rect.left + self.rect.width * blood,self.rect.top -5),3)  #画血条
     
    def shot(self):       
         for angle in range(-90,120,15):
             b = Boss_Bullet(self.rect,angle)
             self.bullets.add(b)
                 
         
    def draw(self):
        self.screen.blit(self.image, self.rect)
        self.drawBlood(self.screen)
        
        
    def preDraw(self):
        DCI.add(self)         
         
             
        

Aliens_Group、Bonus、Stone、Meteor等几乎一样,只是插图和大小、速度等不一致,只列出一个:

Stone.py:

import pygame
import random
import math
from pygame.sprite import Sprite
from Codes.Base.GameSettings import GSeI
from Codes.Base.Screen import SI
from Codes.Common.DrawBase import DrawOn,DCI

class Stone(Sprite,DrawOn):
    def __init__(self):
        super(Stone, self).__init__()
        super(Stone,self).definePriority(3)
        self.screen=SI.screen
        self.image = pygame.image.load('images/stone.png').convert_alpha()
        self.scale=random.randint(80,160)
        self.image = pygame.transform.scale(self.image,(self.scale,self.scale))
        self.r=random.randint(30,150)
        self.image=pygame.transform.rotate(self.image, self.r)
        self.rect = self.image.get_rect()
        self.dir=random.randint(70,110)#运动的偏转角度 取值为30度到150度
        self.theta=self.dir*math.pi/180#转为弧度制 便于计算
        self.v=random.uniform(1,2)#总速度为100-300
        self.a=random.uniform(1,1.01)#加速度
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height
        self.rect.center=(random.randint(10,GSeI.screen_width),30)#随机生成点的位置
        self.x = float( self.rect.x )
        self.y = float( self.rect.y )

    def draw(self):
        self.screen.blit(self.image, self.rect)

    def preDraw(self):
        DCI.add(self)

    def update(self,delta):
        self.x+=math.cos(self.theta)*self.v
        self.y+=math.sin(self.theta)*self.v
        self.v*=self.a
        self.rect.x =self.x
        self.rect.y=self.y
        self.rect.center=(self.x,self.y)
        self.preDraw()


    def check_edges(self):
        screen_rect =SI.screen.get_rect()
        if self.rect.right >= screen_rect.right:
            return True
        elif self.rect.left <=0:
            return True

Boss_Bullet和Bullet很相似:

import pygame
import math
from Codes.Common.DrawBase import DrawOn,DCI
from Codes.Base.Screen import SI

class Boss_Bullet(pygame.sprite.Sprite,DrawOn):  #BOSS的子弹,初步想法为同时向不同方向发射子弹
    def __init__(self,position,angle):
        super(Boss_Bullet,self).__init__()
        super(Boss_Bullet,self).definePriority(3)
        self.speed = 5
        self.angle = angle
        self.screen=SI.screen
        self.image = pygame.image.load("images/bullet.png").convert_alpha()
        self.image = pygame.transform.rotate(self.image,angle)
        self.rect = self.image.get_rect()
        lenB = position.width // 2
        self.rect.left = math.ceil(position.centerx + lenB * math.sin(math.radians(angle)))
        self.rect.top = math.ceil(position.centery + lenB * math.cos(math.radians(angle)))
        
    def update(self):
        x_move = math.ceil(self.speed * math.sin(math.radians(self.angle)))
        y_move = math.ceil(self.speed * math.cos(math.radians(self.angle)))
        self.rect.left += x_move
        self.rect.top += y_move
        self.preDraw()
        
    def draw(self):
        self.screen.blit(self.image, self.rect)
             
    def preDraw(self):
        DCI.add(self)       

特殊武器一——霰弹枪Shotgun:

似乎和Bullets也差不了太多。

import pygame
import math
from pygame.sprite import Sprite
from Codes.Base.GameSettings import GSeI
from Codes.Common.DrawBase import DrawOn,DCI
from Codes.Base.Screen import SI

class Bullet_Shotgun(Sprite,DrawOn):

    def __init__(self):
        super(Bullet_Shotgun, self).__init__()
        super(Bullet_Shotgun,self).definePriority(3)

    def init(self,host,theta):
        self.screen = SI.screen
        self.image = pygame.image.load('images/bullet_shotgun.png').convert_alpha()
        self.image = pygame.transform.scale(self.image,(int(GSeI.bullet_width),int(GSeI.bullet_height)))
        self.dir=theta#倾角,默认为90度
        self.image=pygame.transform.rotate(self.image, 90-self.dir)        
        self.rect = self.image.get_rect()
        self.rect.centerx = host.rect.centerx
        self.rect.top = host.rect.top
        self.y = float(self.rect.y)
        self.x = float(self.rect.x)
        self.speed_factor = GSeI.bullet_speed_factor
        
    def update(self,delta):
        self.theta=self.dir*math.pi/180     
        self.y-=self.speed_factor*delta*math.sin(self.theta)
        self.x-=self.speed_factor*delta*math.cos(self.theta)        
        self.rect.y=self.y
        self.rect.x=self.x
        self.preDraw()

    def preDraw(self):
        DCI.add(self)
    def draw(self):
        self.screen.blit(self.image, self.rect)



特殊武器二——榴弹枪Bullet_Shotgun:

这个和Bullets除了贴图、大小不一样外其他基本一致。

特殊武器三——激光枪Bullet_Light:

这个和其他子弹有所不同,激光波不太好用子弹移动来实现,所以做了个激光的静态贴图来模拟动态激光,子弹设置为在一段时间内不断释放,初始化函数中贴图为一张超过屏幕的光条,刷新函数只需要根据飞机的位置更新其左右位置和贴图的下部位置即可。

import pygame
from pygame.sprite import Sprite
from Codes.Base.GameSettings import GSeI
from Codes.Common.DrawBase import DrawOn,DCI
from Codes.Base.Screen import SI

class Bullet_Light(Sprite,DrawOn):

    def __init__(self):
        super(Bullet_Light,self).__init__()
        super(Bullet_Light,self).definePriority(30)

    def init(self,host):
        self.screen = SI.screen
        self.image = pygame.image.load('images/flow.jpg').convert_alpha()
        self.image = pygame.transform.scale(self.image,(int(GSeI.light_width),int(GSeI.light_height)))       
        self.rect = self.image.get_rect()
        self.rect.centerx = host.rect.centerx
        self.rect.bottom = host.rect.bottom
        self.y = float(self.rect.y)
        self.x = float(self.rect.x)
        self.speed_factor = GSeI.bullet_speed_factor
        
    def update(self,delta,host):
        self.rect.y=self.y
        self.rect.x=host.rect.x+60-0.5*GSeI.light_width
        self.rect.bottom = host.rect.top
        self.preDraw();

    def preDraw(self):
        DCI.add(self)
    def draw(self):
        self.screen.blit(self.image, self.rect)

子弹雨Bullet_Barrage:

第四章地方单位的主力输出,在初始化函数中随机出现在四边,其他相同。

import pygame
import math
import random
from pygame.sprite import Sprite
from Codes.Base.GameSettings import GSeI
from Codes.Common.DrawBase import DrawOn,DCI
from Codes.Base.Screen import SI
class Bullet_Barrage(Sprite,DrawOn):

    def __init__(self):
        super(Bullet_Barrage, self).__init__()
        super(Bullet_Barrage,self).definePriority(3)

    def init(self):
        self.screen = SI.screen
        self.image = pygame.image.load('images/bullet.png').convert_alpha()
        self.image = pygame.transform.scale(self.image,\
                    (int(GSeI.alien_bullet_width),int(GSeI.alien_bullet_height)))
        pos_x,pos_y=0,0
        t=random.randint(0,3)#四个边 左下右上
        if t%2==0:#左右
            pos_y=random.randint(30,800)
            if t==0:
                pos_x=0
                self.theta=random.randint(135,225)
            else:
                pos_x=1200
                self.theta=random.randint(315,405)
        else:
            pos_x=random.randint(0,1200)
            if t==1:
                pos_y=800
                self.theta=random.randint(45,135)
            else:
                pos_y=30  
                self.theta=random.randint(225,315)


        self.image=pygame.transform.rotate(self.image, 90-self.theta)
        self.rect = self.image.get_rect() 
        self.rect.bottomleft=(pos_x,pos_y) 
        
        self.y = float(self.rect.y)
        self.x = float(self.rect.x)
        
        
        self.speed_factor = GSeI.bullet_speed_factor
        self.theta=self.theta*math.pi/180

    def update(self,delta,host):#host=1 机主 host=0 敌机
        v_delete=GSeI.xuruo*(5-GSeI.xuruo)/6.25
        if host==1 or GSeI.ding<=0:
            self.y-=self.speed_factor*delta*math.sin(self.theta)*(1-v_delete)
            self.x-=self.speed_factor*delta*math.cos(self.theta)*(1-v_delete)
        self.rect.y=self.y
        self.rect.x=self.x
        self.preDraw();

    def preDraw(self):
        DCI.add(self)
    def draw(self):
        self.screen.blit(self.image, self.rect)


反弹弹Bullet_Bound:

敌对单位,到达边缘后反弹,其他相同,其check_edge函数更新为:

    def check_edges(self):
        screen_rect =SI.screen.get_rect()
        if self.rect.right >= screen_rect.right or self.rect.left <=0 :
            return 1#theta-pi-thepa
        elif self.rect.bottom >= screen_rect.bottom or self.rect.top <=0 :
            return 2#theta=2*pi-theta

在Battle里控制,根据不同的返回值更改反弹。也可以在更新函数中调用。

跟踪弹:Bullet_Track:

第四章中敌方稳定指向性输出单位,每次刷新的朝向为当前飞机的位置,其他相同,其更新函数为:

    def update(self,delta,host):
        if GSeI.ding<=0:
            distance_x=host.rect.centerx-self.x
            distance_y=host.rect.centery-self.y
            self.y+=self.speed_factor*delta*distance_y/math.sqrt(distance_x**2+distance_y**2)
            self.x+=self.speed_factor*delta*distance_x/math.sqrt(distance_x**2+distance_y**2)
            self.rect.y=self.y
            self.rect.x=self.x
        self.preDraw()

其中,host为飞机。

接下来介绍不同界面。


 

 

 

 

 

    

 

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这里是一个简单的Pygame飞机大战游戏示例: ```python import pygame import random # 初始化 Pygame pygame.init() # 创建游戏窗口 screen_width = 480 screen_height = 700 screen = pygame.display.set_mode((screen_width, screen_height)) # 设置游戏标题 pygame.display.set_caption("飞机大战") # 加载背景图片 background = pygame.image.load("images/background.png").convert() # 加载游戏音效 pygame.mixer.music.load("sound/game_music.ogg") pygame.mixer.music.set_volume(0.2) pygame.mixer.music.play(-1) bullet_sound = pygame.mixer.Sound("sound/bullet.wav") bullet_sound.set_volume(0.2) enemy_down_sound = pygame.mixer.Sound("sound/enemy_down.wav") enemy_down_sound.set_volume(0.2) game_over_sound = pygame.mixer.Sound("sound/game_over.wav") game_over_sound.set_volume(0.2) # 加载玩家飞机图片 player_image = pygame.image.load("images/player.png").convert_alpha() # 加载子弹图片 bullet_image = pygame.image.load("images/bullet.png").convert_alpha() # 加载敌机图片 enemy_images = [ pygame.image.load("images/enemy1.png").convert_alpha(), pygame.image.load("images/enemy2.png").convert_alpha(), pygame.image.load("images/enemy3.png").convert_alpha(), ] # 定义玩家飞机类 class Player(pygame.sprite.Sprite): def __init__(self): super().__init__() self.image = player_image self.rect = self.image.get_rect() self.rect.midbottom = (screen_width // 2, screen_height - 30) self.speed = 8 self.bullets = pygame.sprite.Group() def update(self, keys): if keys[pygame.K_LEFT] and self.rect.left > 0: self.rect.x -= self.speed if keys[pygame.K_RIGHT] and self.rect.right < screen_width: self.rect.x += self.speed def shoot(self): bullet = Bullet(self.rect.centerx, self.rect.top) self.bullets.add(bullet) bullet_sound.play() # 定义子弹类 class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.image = bullet_image self.rect = self.image.get_rect() self.rect.centerx = x self.rect.bottom = y self.speed = -10 def update(self): self.rect.y += self.speed if self.rect.bottom < 0: self.kill() # 定义敌机类 class Enemy(pygame.sprite.Sprite): def __init__(self): super().__init__() self.image = random.choice(enemy_images) self.rect = self.image.get_rect() self.rect.x = random.randint(0, screen_width - self.rect.width) self.rect.y = random.randint(-200, -50) self.speed = random.randint(1, 4) self.health = 1 def update(self): self.rect.y += self.speed if self.rect.top > screen_height: self.kill() # 创建游戏对象 player = Player() enemies = pygame.sprite.Group() all_sprites = pygame.sprite.Group() all_sprites.add(player) # 设置游戏主循环 clock = pygame.time.Clock() score = 0 game_over = False while not game_over: clock.tick(60) # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True # 检测玩家按键 keys = pygame.key.get_pressed() if keys[pygame.K_SPACE]: player.shoot() # 更新玩家和子弹 player.update(keys) player.bullets.update() # 检测子弹和敌机碰撞 for bullet in player.bullets: enemies_hit = pygame.sprite.spritecollide(bullet, enemies, True) for enemy in enemies_hit: enemy_down_sound.play() score += 100 bullet.kill() # 更新敌机 if random.randint(1, 30) == 1: enemy = Enemy() enemies.add(enemy) all_sprites.add(enemy) enemies.update() # 检测玩家与敌机碰撞 if pygame.sprite.spritecollide(player, enemies, True): game_over_sound.play() game_over = True # 绘制游戏界面 screen.blit(background, (0, 0)) all_sprites.draw(screen) # 显示得分 font = pygame.font.SysFont(None, 36) score_text = font.render("得分: {}".format(score), True, (255, 255, 255)) screen.blit(score_text, (10, 10)) # 更新屏幕 pygame.display.update() # 游戏结束 pygame.quit() ``` 你可以在代码中看到,程序使用了 Pygame 绘图模块来创建游戏窗口、加载图片和播放音效。游戏中有三个主要的类:Player、Bullet和Enemy。其中,Player类表示玩家飞机,Bullet类表示子弹,Enemy类表示敌机。游戏主循环中,程序不断更新玩家和子弹位置,检测子弹和敌机碰撞,更新敌机位置,检测玩家与敌机碰撞,绘制游戏界面,并在游戏结束时退出 Pygame

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值