# coding=utf-8 # Version:python3.6.1 __date__ = '2018/9/20 18:51' __author__ = 'Lgsp_Harold' import pygame, sys, time from random import randint from pygame.locals import * # 坦克大戰主窗口 class TankMain(object): width = 600 height = 500 my_tank_missile_list = [] # 我方子彈列表 my_tank = None # enemy_list = [] # 敵方坦克列表 wall=None enemy_list = pygame.sprite.Group() # 敵方坦克的組 explode_list = [] enemy_missile_list=pygame.sprite.Group() # 開始游戲的方法 def startGame(self): pygame.init() # pygame模塊初始化,加載系統的資源 # 創建一個窗口,窗口大小(寬,高)、窗口的特性(0,RESIZEBLE,RULLscreem) screem = pygame.display.set_mode((TankMain.width, TankMain.height), 0, 32) pygame.display.set_caption("坦克大戰") # 創建一堵牆 TankMain.wall = Wall(screem,65,160,30,120) # my_tank=My_Tank(screem) # 創建一個我方坦克,坦克顯示在屏幕的中下部位置 TankMain.my_tank = My_Tank(screem) # 創建一個我方坦克,坦克顯示在屏幕的中下部位置 if len(TankMain.enemy_list)==0: # enemy_list=[] for i in range(1, 6): # 游戲開始時初始化5個敵方坦克 # TankMain.enemy_list.append(Enemy_Tank(screem)) TankMain.enemy_list.add(Enemy_Tank(screem)) # 把敵方坦克放到組里面 while True: if len(TankMain.enemy_list) < 5: TankMain.enemy_list.add(Enemy_Tank(screem)) # 把敵方坦克放到組里面 # color RGB(0,0,0) # 設置窗口屏幕背景顏色 screem.fill((0, 0, 0)) # 面向過程的寫法 # pygame.draw.rect(screem,(0,255,0),Rect(400,30,100,30),5) # 顯示左上角的文字 for i, text in enumerate(self.write_text(), 0): screem.blit(text, (0, 5 + (15 * i))) # 顯示游戲中的牆,並且對牆和其他對象進行碰撞檢測 TankMain.wall.display() TankMain.wall.hit_tank() self.get_event(TankMain.my_tank,screem) # 獲取事件,根據獲取事件進行處理 if TankMain.my_tank: TankMain.my_tank.hit_enemy_missile() # 我方坦克和敵方的炮彈碰撞檢測 if TankMain.my_tank and TankMain.my_tank.live: TankMain.my_tank.display() # 在屏幕上顯示我方坦克 TankMain.my_tank.move() # 在屏幕上移動的我方坦克 else: # del(TankMain.my_tank) # TankMain.my_tank=None # print("Game Over") # sys.exit() TankMain.my_tank=None # 顯示和隨機移動所有的敵方坦克 for enemy in TankMain.enemy_list: enemy.display() enemy.random_move() enemy.random_fire() # 顯示所有的我方炮彈 for m in TankMain.my_tank_missile_list: if m.live: m.display() m.hit_tank() # 炮彈打中敵方坦克 m.move() else: TankMain.my_tank_missile_list.remove(m) # 顯示所有的敵方炮彈 for m in TankMain.enemy_missile_list: if m.live: m.display() m.move() else: TankMain.enemy_missile_list.remove(m) for explode in TankMain.explode_list: explode.display() # 顯示重置 time.sleep(0.05) # 每次休眠0.05秒跳到下一幀 pygame.display.update() # 獲取所有的事件(敲擊鍵盤,鼠標點擊事件) def get_event(self, my_tank,screem): for event in pygame.event.get(): if event.type == QUIT: # 程序退出 self.stopGame() if event.type == KEYDOWN and (not my_tank) and event.key == K_n: TankMain.my_tank = My_Tank(screem) if event.type == KEYDOWN and my_tank: if event.key == K_LEFT or event.key == K_a: my_tank.direction = "L" my_tank.stop = False # my_tank.move() if event.key == K_RIGHT or event.key == K_d: my_tank.direction = "R" my_tank.stop = False # my_tank.move() if event.key == K_UP or event.key == K_w: my_tank.direction = "U" my_tank.stop = False # my_tank.move() if event.key == K_DOWN or event.key == K_s: my_tank.direction = "D" my_tank.stop = False # my_tank.move() if event.key == K_ESCAPE: self.stopGame() if event.key == K_SPACE: m = my_tank.fire() m.good = True # 我方坦克發射的炮彈,好炮彈 TankMain.my_tank_missile_list.append(m) if event.type == KEYUP and my_tank: if event.key == K_LEFT or K_RIGHT or K_UP or K_DOWN: my_tank.stop = True if event.type == MOUSEBUTTONUP: pass # 關閉游戲 def stopGame(self): sys.exit() # 在游戲窗口內左上角顯示文字內容 def write_text(self): font = pygame.font.SysFont("方正蘭亭超細黑簡體", 16) # 定義一個字體 # 文字,抗鋸齒,字體顏色 text_sf1 = font.render("敵方坦克數量為:%d" % len(TankMain.enemy_list), True, (255, 0, 0)) # 根據字體創建一個文件的圖像 text_sf2 = font.render("我方坦克炮彈數量為:%d" % len(TankMain.my_tank_missile_list), True, (255, 0, 0)) # 根據字體創建一個文件的圖像 return text_sf1, text_sf2 # 坦克大戰游戲中所有對象的父類 class BaseItem(pygame.sprite.Sprite): def __init__(self, screem): pygame.sprite.Sprite.__init__(self) # 所有對象共享的屬性 self.screem = screem # 把坦克對應圖片顯示在游戲窗口上 # 在游戲屏幕中顯示當前游戲的對象 def display(self): if self.live: self.image = self.images[self.direction] self.screem.blit(self.image, self.rect) # 把圖片畫在屏幕上 # 坦克公共父類 class Tank(BaseItem): # 定義類屬性,所有坦克對象高和寬都是一樣 width = 50 height = 50 def __init__(self, screem, left, top): super().__init__(screem) # self.screem=screem # 坦克在移動或者顯示過程中需要用到當前游戲的屏幕 self.direction = 'D' # 坦克的方向,默認方向向下(上下左右) self.speed = 5 # 坦克移動的速度 self.stop = False self.images = {} # 坦克的所有圖片,key:方向,value:圖片路徑(surface) self.images['L'] = pygame.image.load("../img/p1tankL.gif") self.images['R'] = pygame.image.load("../img/p1tankR.gif") self.images['U'] = pygame.image.load("../img/p1tankU.gif") self.images['D'] = pygame.image.load("../img/p1tankD.gif") self.image = self.images[self.direction] # 坦克的圖片由方向決定 self.rect = self.image.get_rect() self.rect.left = left self.rect.top = top self.live = True # 決定坦克是否消滅了 self.oldTop=self.rect.top self.oldLeft=self.rect.left def stay(self): self.rect.left=self.oldLeft self.rect.top=self.oldTop # 坦克移動方法 def move(self): if not self.stop: # 如果坦克不是停止狀態 self.oldLeft=self.rect.left self.oldTop=self.rect.top if self.direction == "L": # 如果坦克的方向向左,那么只需要改坦克的left就可以了,left在減少 if self.rect.left > 0: # 判斷坦克是否在左邊的邊界上 self.rect.left -= self.speed else: self.rect.left = 0 elif self.direction == "R": if self.rect.right < TankMain.width: self.rect.right += self.speed else: self.rect.right = TankMain.width elif self.direction == "U": if self.rect.top > 0: self.rect.top -= self.speed else: self.rect.top = 0 elif self.direction == "D": if self.rect.bottom < TankMain.height: self.rect.bottom += self.speed else: self.rect.bottom = TankMain.height def fire(self): m = Missile(self.screem, self) return m # 我方坦克類 class My_Tank(Tank): def __init__(self, screem): super().__init__(screem, 275, 400) # 創建一個我方坦克,坦克顯示在屏幕的中下部位置 self.stop = True self.live = True def hit_enemy_missile(self): hit_list=pygame.sprite.spritecollide(self,TankMain.enemy_missile_list,False) for m in hit_list: # 我方坦克中彈 m.live=False TankMain.enemy_missile_list.remove(m) self.live=False explode = Explode(self.screem,self.rect) TankMain.explode_list.append(explode) # 敵方坦克類 class Enemy_Tank(Tank): def __init__(self, screem): super().__init__(screem, randint(1, 5) * 100, 200) self.speed = 3 self.step = 12 # 坦克按照某個方向移動的步數 self.get_random_direction() def get_random_direction(self): r = randint(0, 4) # 得到一個坦克移動方向和停止的隨機數 if r == 4: self.stop = True elif r == 2: self.direction = "L" self.stop = False elif r == 0: self.direction = "R" self.stop = False elif r == 1: self.direction = "U" self.stop = False elif r == 3: self.direction = "D" self.stop = False # 敵方坦克按照一個確定的隨機方向,連續移動12步,然后再次改變方向 def random_move(self): if self.live: if self.step == 0: self.get_random_direction() self.step = 12 else: self.move() self.step -= 1 #隨機開火 def random_fire(self): r=randint(0,50) if r==10: m=self.fire() TankMain.enemy_missile_list.add(m) else: return # 炮彈類 class Missile(BaseItem): width = 5 height = 5 def __init__(self, screem, tank): super().__init__(screem) self.tank = tank self.direction = tank.direction # 炮彈的方向由所發射的坦克方向決定 self.speed = 12 # 炮彈移動的速度 enemymissileImg = pygame.image.load("../img/enemymissile.gif") self.images = {} # 炮彈的所有圖片,key:方向,value:圖片路徑(surface) self.images['L'] = enemymissileImg self.images['R'] = enemymissileImg self.images['U'] = enemymissileImg self.images['D'] = enemymissileImg self.image = self.images[self.direction] # 坦克的圖片由方向決定 self.rect = self.image.get_rect() # 炮彈的邊界 # 炮彈坐標 self.rect.left = tank.rect.left + (tank.width - self.width) / 2 self.rect.top = tank.rect.top + (tank.height - self.height) / 2 self.live = True # 決定炮彈是否消滅了 self.good = False def move(self): if self.live: # 如果炮彈還存在 if self.direction == "L": # 如果坦克的方向向左,那么只需要改坦克的left就可以了,left在減少 if self.rect.left > 0: # 判斷坦克是否在左邊的邊界上 self.rect.left -= self.speed else: self.live = False elif self.direction == "R": if self.rect.right < TankMain.width: self.rect.right += self.speed else: self.live = False elif self.direction == "U": if self.rect.top > 0: self.rect.top -= self.speed else: self.live = False elif self.direction == "D": if self.rect.bottom < TankMain.height: self.rect.bottom += self.speed else: self.live = False # 炮彈擊中坦克,第一種我方炮彈擊中敵方坦克;第二種敵方炮彈擊中我方坦克 def hit_tank(self): if self.good: # 如果炮彈是我方的炮彈 hit_list = pygame.sprite.spritecollide(self,TankMain.enemy_list,False) for e in hit_list: e.live=False TankMain.enemy_list.remove(e) # 如果敵方坦克被擊中,從列表中刪除敵方坦克 self.live=False expload = Explode(self.screem,e.rect) # 產生一個爆炸對象 TankMain.explode_list.append(expload) # 爆炸類 class Explode(BaseItem): def __init__(self, screem, rect): super().__init__(screem) self.live = True self.images = [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"),\ pygame.image.load("../img/blast6.gif"),\ pygame.image.load("../img/blast7.gif"),\ pygame.image.load("../img/blast8.gif")] self.step = 0 self.rect = rect # 爆炸的位置和發生爆炸前,炮彈碰到的坦克位置一樣。在構建爆炸的時候把坦克的rect傳遞進來。 # display方法在整個游戲運行過程中,循環調用,每隔0.1秒調用一次 def display(self): if self.live: if self.step == len(self.images): # 最后一張爆炸圖片已經顯示 self.live = False else: self.image = self.images[self.step] self.screem.blit(self.image, self.rect) self.step+=1 else: pass # 刪除該對象 # 游戲中的牆 class Wall(BaseItem): def __init__(self,screem,left,top,width,height): super().__init__(screem) self.rect=Rect(left,top,width,height) # self.left=left # self.top=top # self.width=width # self.height=height self.color=(255,0,0) def display(self): self.screem.fill(self.color,self.rect) #針對牆和其他坦克或者炮彈的碰撞檢測 def hit_tank(self): if TankMain.my_tank: is_hit=pygame.sprite.collide_rect(self,TankMain.my_tank) if is_hit: TankMain.my_tank.stop=True TankMain.my_tank.stay() if len(TankMain.enemy_list)!=0: hit_list=pygame.sprite.spritecollide(self,TankMain.enemy_list,False) for e in hit_list: e.stop=True e.stay() # 敵方炮彈擊中牆,子彈消失 if TankMain.enemy_missile_list: enemy_missile_hit_list=pygame.sprite.spritecollide(self,TankMain.enemy_missile_list,False) for e in enemy_missile_hit_list: e.stop=True e.live=False # 我方炮彈擊中牆,子彈消失 if TankMain.my_tank_missile_list: my_tank_missile_hit_list=pygame.sprite.spritecollide(self,TankMain.my_tank_missile_list,False) for e in my_tank_missile_hit_list: e.stop=True e.live=False tankMain = TankMain() tankMain.startGame() if __name__ == '__main__': pass
圖片下載:https://pan.baidu.com/s/1bqlGB0