天天看點

pygame-飛機大戰(下·二)

一、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為飛機。

接下來介紹不同界面。