Python 坦克大戰小遊戲進階 版本號v1.14
阿新 • • 發佈:2018-12-19
python初階
''' v1.14 實現牆壁類 以及 子彈與牆壁的碰撞 ''' import pygame,time,random SCREEN_WIDTH = 900 SCREEN_HEIGHT = 550 VERSION = 'V1.14' # 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) #展示我方坦克 def showMytank(self): MainGame.tank1.displayTank() # v1.08 新增將 我方坦克移動程式碼 移動位置 if not MainGame.tank1.stop: # 我方坦克移動 MainGame.tank1.move() # 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 新增敵方坦克射擊,並把敵方子彈加入列表 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.08 優化移動 def move(self): # 移動,基於在指定的方向移動 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.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) # 音效類 class Audio(): pass #建立一個主邏輯類的物件 game = MainGame() # 開始遊戲 game.startGame()