1. 程式人生 > >python t坦克大戰小遊戲程序 版本號v1.16

python t坦克大戰小遊戲程序 版本號v1.16

python 初階

'''
v1.16 實現音效類
'''
import pygame,time,random
SCREEN_WIDTH = 900
SCREEN_HEIGHT = 550
VERSION = 'V1.16'
# v1.07新增 記錄敵方坦克的數量
ENEMY_TANK_COUNT = 5
# 主邏輯類
class MainGame():
    # 遊戲主視窗
    window = None
    # 我方坦克(唯一性)設定成類屬性
    tank1 = None
    # v1.07新增儲存敵方坦克的列表
    enemy_tanklist = []
    # v1.09 新增儲存我方子彈的列表
    mybullet_list = []
    # v1.11 新增儲存敵方子彈的列表
    enemybullet_list = []
    # v1.13 新增 儲存爆炸效果的列表
    explode_list = []
    # v.14 新增 建立儲存牆壁的列表
    wall_list = []
    def startGame(self):
        # 呼叫視窗初始化方法
        pygame.display.init()
        # 在視窗左上角設定遊戲標題
        pygame.display.set_caption('坦克大戰'+VERSION)
        # 建立一個視窗螢幕顯示錶面
        MainGame.window = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
        # 呼叫建立我方坦克的方法
        self.createMytank()
        # 呼叫建立敵方坦克的方法
        self.createEnemytank()
        # v1.14 新增 呼叫建立牆壁的方法
        self.createWalls()
        while True:
            # 填充視窗背景色
            MainGame.window.fill((100,100,200))
            # 將獲取的事件型別在填充完視窗背景色後時刻處於迴圈中
            self.getEvents()
            # v1.14 新增 呼叫展示牆壁的方法
            self.showWalls()
            # 展示我方坦克
            self.showMytank()
            # 呼叫展示敵方坦克的方法
            self.showEnemyTank()
            # v1.09 新增呼叫展示我方子彈的方法
            self.showMyBullet()
            # v1.11 新增呼叫展示敵方子彈的方法
            self.showEnemyBullet()
            # v1.13 呼叫展示爆炸效果的方法
            self.showExplode()
            # 更新
            pygame.display.update()
            # v1.06 新增程式休眠,優化坦克的移動速度
            time.sleep(0.025)
    # 獲取所有事件處理的方法
    def getEvents(self):
        # 獲取佇列中的所有事件,遍歷事件,對type為QUIT和KEYDOWN的兩種事件型別進行處理
        eventList = pygame.event.get()
        # 遍歷所有事件
        for e in eventList:
            # 當事件型別是QUIT時,退出遊戲
            if e.type == pygame.QUIT:
                self.showMytank()
                # 退出遊戲
                self.gameOver()
            #  當事件型別是KEYDOWN時,進行細化處理
            elif e.type == pygame.KEYDOWN:
                # 按下鍵盤上的向上按鍵時的處理
                if e.key == pygame.K_UP:
                    print('向上移動')
                    MainGame.tank1.direction = 'U'
                    # v1.06修改坦克的移動狀態
                    MainGame.tank1.stop = False
                # 按下鍵盤上的向下按鍵時的處理
                elif e.key == pygame.K_DOWN:
                    print('向下移動')
                    MainGame.tank1.direction = 'D'
                    # v1.06修改坦克的移動狀態
                    MainGame.tank1.stop = False
                # 按下鍵盤上的向左按鍵時的處理
                elif e.key == pygame.K_LEFT:
                    print('向左移動')
                    MainGame.tank1.direction = 'L'
                    MainGame.tank1.stop = False
                # 按下鍵盤上的向右按鍵時的處理
                elif e.key == pygame.K_RIGHT:
                    print('向右移動')
                    MainGame.tank1.direction = 'R'
                    MainGame.tank1.stop = False
                # 按下鍵盤上的空格按鍵時的處理
                elif e.key == pygame.K_SPACE:
                    print('biubiu~')
                    # v1.09 新增呼叫發射方法,並將子彈裝進列表
                    b = MainGame.tank1.shoot()
                    # v1.11 新增我方子彈數量控制
                    if len(MainGame.mybullet_list) < 3:
                        MainGame.mybullet_list.append(b)
                    print('子彈的數量%d'%len(MainGame.mybullet_list))
            #v1.06新增按鍵鬆開的事件處理
            elif e.type == pygame.KEYUP:
                if e.key == pygame.K_UP or e.key == pygame.K_DOWN or\
                    e.key == pygame.K_LEFT or e.key == pygame.K_RIGHT:
                    # 將坦克的移動狀態改為停止
                    MainGame.tank1.stop = True
    # 建立我方坦克
    def createMytank(self):
        # 建立我方坦克並賦予其位置屬性座標
        MainGame.tank1 = MyTank(SCREEN_WIDTH/2,SCREEN_HEIGHT/3*2)
        # v1.15 新增 建立我方坦克時,播放背景音效
        audio = Audio('img/start.wav')
        audio.playAudio()
    #展示我方坦克
    def showMytank(self):
        MainGame.tank1.displayTank()
        # v1.08 新增將 我方坦克移動程式碼 移動位置
        if not MainGame.tank1.stop:
            # 我方坦克移動
            MainGame.tank1.move()
            # v1.15 呼叫是否撞牆的方法
            MainGame.tank1.hitWall()
    # v1.07建立敵方坦克
    def createEnemytank(self):
        # 迴圈建立敵方坦克
        for i in range(ENEMY_TANK_COUNT):
            num = random.randint(1,7)
            # v1.08新增 隨機速度
            randomspeed = random.randint(3,10)
            # 建立第一個敵方坦克,出現位置為y=150,x隨機出現在(100-700),坦克移動的隨機速度是randomspeed
            # v1.08新增呼叫修改後的init方法
            etank = EnemyTank(100*num,150,randomspeed)
            # 建立敵方坦克列表,存入所有的敵方坦克
            MainGame.enemy_tanklist.append(etank)
    # v1.07展示敵方坦克
    def showEnemyTank(self):
        # 遍歷展示敵方坦克
        for etank in MainGame.enemy_tanklist:
            #v1.12 新增 根據敵方坦克狀態,進行相關業務處理
            if etank.live:
               etank.displayTank()
               # v1.08 新增敵方坦克的移動
               etank.move()
               # v1.11 新增敵方坦克射擊,並把敵方子彈加入列表
               # v.15 呼叫是否撞牆的方法
               etank.hitWall()
               b = etank.shoot()
               # if b != None:或 if b:  即在敵方坦克重寫射擊方法中,如果隨機概率是5%,把敵方子彈新增到敵方子彈列表中
               if b != None:
                   MainGame.enemybullet_list.append(b)
            else:
               MainGame.enemy_tanklist.remove(etank)
    # v1.09 展示我方子彈的方法
    def showMyBullet(self):
        for b in MainGame.mybullet_list:
            # 如果子彈活著,展示並移動子彈
            if b.live:
                b.displayBullet()
                # v1.10 新增呼叫子彈的移動方法
                b.move()
                #如果子彈死亡,移除子彈,給子彈列表騰空間,保證打到牆上的子彈消失
                #v1.12 新增呼叫是否打中敵方坦克
                b.hitEnemyTank()
                # v1.14 新增 呼叫是否打中牆壁的方法
                b.hitWall()
            else:
                MainGame.mybullet_list.remove(b)
    # v1.11 新增展示敵方子彈方法
    def showEnemyBullet(self):
        for b in MainGame.enemybullet_list:
            if b.live:
                b.displayBullet()
                b.move()
                # v1.14 新增 呼叫是否打中牆壁的方法
                b.hitWall()
            else:
                MainGame.enemybullet_list.remove(b)
    # v1.13 展示爆炸效果
    def showExplode(self):
        for e in MainGame.explode_list:
            if e.live:
                e.displayExplode()
            else:
                MainGame.explode_list.remove(e)
    # v1.14 建立牆壁的方法
    def createWalls(self):
        for i in range(1,7):
            w = Wall(130*i,300)
            MainGame.wall_list.append(w)
    # v1.14 展示牆壁的方法
    def showWalls(self):
        for wall in MainGame.wall_list:
            wall.displayWall()

    def gameOver(self):
        exit()
# 基本坦克類
# v1.12 新增基本坦克類呼叫精靈類
class BaseTank( pygame.sprite.Sprite):
    # 基本坦克屬性 位置 方向 速度 圖片
    def __init__(self):
        # v1.12 呼叫精靈類的初始化
        pygame.sprite.Sprite.__init__(self)
        self.direction = None
        self.rect = None
        self.images = None
        self.image = None
        self.speed = 0
        #v1.06新增屬性,用來控制坦克是否移動
        self.stop = True
        # v1.12 新增基本屬性,判斷坦克是否還活著
        self.live = True
        # v1.15 新增 兩個基本屬性記錄坦克移動之前的座標
        self.oldx = None
        self.oldy = None
    # v1.08 優化移動
    def move(self):
        # v1.15 移動之前先記錄下座標
        self.oldx = self.rect.centerx
        self.oldy = self.rect.centery
        # 移動,基於在指定的方向移動
        if self.direction == 'U':
            if self.rect.centery > self.rect.height/2:
                self.rect.centery -= self.speed
        elif self.direction == 'D':
            if self.rect.centery < SCREEN_HEIGHT - self.rect.height/2:
                self.rect.centery += self.speed
        elif self.direction == 'L':
            if self.rect.centerx > self.rect.height/2:
                self.rect.centerx -= self.speed
        elif self.direction == 'R':
            if self.rect.centerx < SCREEN_WIDTH - self.rect.height/2:
                self.rect.centerx += self.speed
     # v1.15 新增 封裝還原座標的方法
    def stay(self):
        self.rect.centerx = self.oldx
        self.rect.centery = self.oldy
     # v1.15 新增 坦克撞牆的方法
    def hitWall(self):
        for wall in MainGame.wall_list:
            if pygame.sprite.collide_rect(self,wall):
                self.stay()
     # v1.09 新增射擊方法
    def shoot(self):
        bullet = Bullet(self)
        return bullet
# 我方坦克類
class MyTank(BaseTank):
    def __init__(self,x,y):
        #引用父類屬性
        super(MyTank, self).__init__()
        # 設定具體的圖片集
        self.images = {
            'U':pygame.image.load('img/p1tankU.gif'),
            'D':pygame.image.load('img/p1tankD.gif'),
            'L':pygame.image.load('img/p1tankL.gif'),
            'R':pygame.image.load('img/p1tankR.gif')
                       }
        # 我方坦克的初始方向
        self.direction = 'U'
        # 設定坦克的圖片(self.image 返回的是一個surface)
        self.image = self.images[self.direction]
        # 先基於影象獲取坦克的位置和大小
        self.rect = self.image.get_rect()
        # 修改坦克座標,改成自定義位置
        self.rect.centerx = x
        self.rect.centery = y
        # 設定坦克速度
        self.speed = 5
    #將我方坦克加入到視窗中
    def displayTank(self):
        self.image = self.images[self.direction]
        # 把坦克的影象(即表面)和位置放到另一個影象或表面視窗
        MainGame.window.blit(self.image,self.rect)

# 敵方坦克類
class EnemyTank(BaseTank):
    # v1.08新增隨機速度引數
    def __init__(self,x,y,randSpeed):
        # v1.08新增呼叫父類的初始化
        super(EnemyTank, self).__init__()
        # 設定具體的圖片集
        self.images = {
            'U':pygame.image.load('img/enemy1U.gif'),
            'D':pygame.image.load('img/enemy1D.gif'),
            'L':pygame.image.load('img/enemy1L.gif'),
            'R':pygame.image.load('img/enemy1R.gif')
                       }
        # v1.07敵方坦克的初始方向為隨機方向
        self.direction = self.randomDirection()
        # 設定坦克的圖片(self.image 返回的是一個surface)
        self.image = self.images[self.direction]
        # 先基於影象獲取坦克的位置和大小
        self.rect = self.image.get_rect()
        # 修改坦克座標,改成自定義位置
        self.rect.centerx = x
        self.rect.centery = y
        # v1.08新增速度為引數傳進來的速度
        self.speed = randSpeed
        # v1.08新增記錄敵方坦克移動的步數
        self.step = 25
        # v1.07生成敵方坦克的隨機方向
    def randomDirection(self):
        num = random.randint(1,4)
        if num == 1:
            return 'U'
        elif num == 2:
            return 'D'
        elif num == 3:
            return 'L'
        elif num == 4:
            return 'R'
    # v1.08新增重寫父類中的移動move方法,方法中新增隨機方向的處理
    def move(self):
        if self.step == 0:
            # 變換方向
            self.direction = self.randomDirection()
            # 將步數重新歸置成25
            self.step = 25
        else:
            super(EnemyTank, self).move()
            self.step -= 1
    # v1.11 新增重寫父類的射擊方法
    def shoot(self):
        num = random.randint(1,100)
        if num <= 5:
            return super(EnemyTank, self).shoot()
    # 將敵方坦克加入到視窗中
    def displayTank(self):
        self.image = self.images[self.direction]
        # 把坦克的影象(即表面)和位置放到另一個影象或表面視窗
        MainGame.window.blit(self.image, self.rect)


#v1.09 新增實現子彈類
# v1.12 新增子彈類繼承於精靈類
class Bullet(pygame.sprite.Sprite):
    def __init__(self,tank):
        # v1.12 新增呼叫精靈類的初始化
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load('img/enemymissile.gif')
        # 讓子彈的方向和坦克的方向保持一致
        self.direction = tank.direction
        # 基於影象獲取子彈的位置和區域大小  子彈的區域預設為左上角
        self.rect = self.image.get_rect()
        # 修改子彈的初始化位置(即子彈的方向和坦克的方向保持一致的情況下,確定子彈的中心點座標,並且座標也隨坦克變動)
        if self.direction == 'U':
            self.rect.centerx = tank.rect.centerx
            self.rect.centery = tank.rect.centery - tank.rect.height/2 - self.rect.height/2
        elif self.direction == 'D':
            self.rect.centerx = tank.rect.centerx
            self.rect.centery = tank.rect.centery + tank.rect.height / 2 + self.rect.height / 2
        elif self.direction == 'L':
            self.rect.centerx = tank.rect.centerx - tank.rect.height/2 - self.rect.height/2
            self.rect.centery = tank.rect.centery
        elif self.direction == 'R':
            self.rect.centerx = tank.rect.centerx + tank.rect.height / 2 + self.rect.height / 2
            self.rect.centery = tank.rect.centery
        #v1.10 新增子彈移動速度
        self.speed = 11
        # v1.10 新增子彈的存活狀態,用來記錄子彈是否活著
        self.live = True
    # v1.12 新增 子彈是否碰撞到敵方坦克 方法
    def hitEnemyTank(self):
        for etank in MainGame.enemy_tanklist:
            # 呼叫pygame.sprite.collide_rect(left,right),判斷子彈與敵方坦克的碰撞
            if pygame.sprite.collide_rect(self,etank):
                # v1.13 產生爆炸效果,並把爆炸效果裝進爆炸效果列表
                explode = Explode(etank.rect)
                MainGame.explode_list.append(explode)
                # 修改子彈的狀態
                self.live = False
                # 修改敵方坦克的狀態
                etank.live = False
    # v1.14 新增 子彈碰撞牆壁的方法
    def hitWall(self):
        for wall in MainGame.wall_list:
            if pygame.sprite.collide_rect(self,wall):
                self.live = False
    # v1.10 新增子彈的移動方法
    def move(self):
        if self.direction == 'U':
            if self.rect.centery > self.rect.height/2:
                self.rect.centery -= self.speed
            else:
                self.live = False
        elif self.direction == 'D':
            if self.rect.centery < SCREEN_HEIGHT - self.rect.height/2:
                self.rect.centery += self.speed
            else:
                self.live = False
        elif self.direction == 'L':
            if self.rect.centerx > self.rect.height / 2:
                self.rect.centerx -= self.speed
            else:
                self.live = False
        elif self.direction == 'R':
            if self.rect.centerx < SCREEN_WIDTH - self.rect.height / 2:
                self.rect.centerx += self.speed
            else:
                self.live = False

    #將子彈的影象展示到遊戲主視窗
    def displayBullet(self):
        MainGame.window.blit(self.image,self.rect)
#v1.13 新增 完善爆炸類
class Explode():
    def __init__(self,rect):
        # 指定一個區域進行爆炸效果的釋放
        self.rect = rect
        self.images = [
            pygame.image.load('img/blast0.gif'),
            pygame.image.load('img/blast1.gif'),
            pygame.image.load('img/blast2.gif'),
            pygame.image.load('img/blast3.gif'),
            pygame.image.load('img/blast4.gif'),
            pygame.image.load('img/blast5.gif')
                       ]
        # 記錄圖片的索引值
        self.step = 0
        self.image = self.images[self.step]
        # 用來判斷爆炸效果是否活著的屬性
        self.live = True
    def displayExplode(self):
        if self.step < len(self.images):
            MainGame.window.blit(self.image,self.rect)
            self.image = self.images[self.step]
            self.step += 1
        else:
            self.step = 0
            self.live = False

#v1.14 完善牆壁類
class Wall(pygame.sprite.Sprite):
    def __init__(self,x,y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load('img/steels.gif')
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.centery = y
    def displayWall(self):
        MainGame.window.blit(self.image,self.rect)
#v1.16 完善音效類
class Audio():
    def __init__(self,music):
        # 對混合模組初始化
        pygame.mixer.init()
        # 載入音樂檔案
        pygame.mixer.music.load(music)
    def playAudio(self):
        # 播放音樂檔案
        pygame.mixer.music.play(5)
#建立一個主邏輯類的物件
game = MainGame()
# 開始遊戲
game.startGame()