1 #! /usr/bin/env python 2 # -*- coding:utf8 -*- 3 ''' 4 *author:wasua 5 *purpose:學習python語言,其中的類以及pygame應用 6 *date:2019/04/20 7 ''' 8 9 ''' 10 類: 11 sprite: 12 1.游戲主界面 13 14 2.坦克:我方坦克\敵方坦克 15 1.移動 16 2.發射炮彈 17 3.炮彈:大炮彈\小炮彈 18 1.撞到 19 2.爆炸(也是一個連續圖片) 20 4.障礙物: 21 1.能否闖過 22 2.能否擊毀 23 24 5.爆炸 25 26 ''' 27 28 import pygame, sys, time 29 from random import randint 30 31 32 class TankMain(object): 33 """坦克大戰的主窗口""" 34 Width = 1000 35 Height = 800 36 live_count = 4 # 3次復活機會 37 my_tank = None 38 #steel_wall = [] 39 #block_wall = [] 40 #grass_wall = [] 41 wall=[] 42 my_tank_missile = [] 43 enemy_list = pygame.sprite.Group() 44 enemy_missile_list = pygame.sprite.Group() 45 explode_list = [] 46 47 # 開始游戲的方法 48 def startGame(self): 49 pygame.init() 50 # 創建一個平面,設置平面大小(寬,高),窗口的屬性(0,RESIZEBLE,FULLSCREEN) 51 screem = pygame.display.set_mode((TankMain.Width, TankMain.Height), 0, 32) 52 # 設置窗口標題 53 pygame.display.set_caption('坦克大戰') 54 for i in range(6):#此處應該編寫一個函數來進行比較好 55 TankMain.wall.append(SteelsWall(screem, 100 + i * 60, 100)) 56 TankMain.wall.append(BlockWall(screem, 700, 100 + i * 60)) 57 TankMain.wall.append(GrassWall(screem, 500, 0 + i * 60)) 58 TankMain.wall.append(GrassWall(screem,50,40)) 59 60 #wall = TankMain.steel_wall + TankMain.grass_wall + TankMain.block_wall 61 TankMain.my_tank = My_TanK(screem) 62 for i in range(0, 20): 63 TankMain.enemy_list.add(Enemy_TanK(screem)) 64 while True: 65 # if len(TankMain.enemy_list)<5:#地獄模式 66 # TankMain.enemy_list.add(Enemy_TanK(screem)) 67 # 顯示牆 68 for i in TankMain.wall: 69 i.display() 70 i.hit_tank() 71 i.hit_missile() 72 if not i.live: 73 TankMain.wall.remove(i) 74 pygame.display.update() # 此處不添加則會導致圖片不顯示 75 # 設置窗口填充(背景---RGB模式) 76 screem.fill((0, 0, 0)) 77 # 顯示左上角的文字 78 for index, text in enumerate(self.write_text(TankMain.enemy_list)): 79 screem.blit(text, (0, 5 + (15 * index))) 80 # screem.blit(self.write_text(TankMain.enemy_list),(0,0)) 81 self.get_event(TankMain.my_tank, screem) 82 if TankMain.my_tank: 83 TankMain.my_tank.hit_enemy_missile() 84 if TankMain.my_tank and TankMain.my_tank.live: 85 TankMain.my_tank.display() 86 TankMain.my_tank.move() 87 else: 88 TankMain.my_tank = None 89 for enemy in TankMain.enemy_list: 90 enemy.display() 91 enemy.random_move() 92 enemy.random_fire() 93 for m in TankMain.my_tank_missile: 94 if m.live: 95 m.display() 96 m.hit_tank() 97 m.move() 98 else: 99 TankMain.my_tank_missile.remove(m) 100 101 for m in TankMain.enemy_missile_list: 102 if m.live: 103 m.display() 104 m.move() 105 else: 106 TankMain.enemy_missile_list.remove(m) 107 108 for explode in TankMain.explode_list: 109 explode.display() 110 # 顯示重置 111 time.sleep(0.1) 112 pygame.display.update() 113 114 # 關閉游戲 115 def stopGame(self): 116 sys.exit() 117 118 # 屏幕左上角顯示文字內容 119 def write_text(self, enemy_list): 120 # 定義字體 121 font = pygame.font.SysFont('微軟雅黑', 15, (255, 255, 255)) 122 # 根據字體創建一個文件圖像 123 text_sf1 = font.render(u'敵方坦克數量為:%d' % len(enemy_list), True, (255, 255, 255)) 124 text_sf2 = font.render(u'生命數量:%d' % (int(TankMain.live_count) - 1), True, (255, 255, 255)) 125 return text_sf1, text_sf2 126 127 # 獲取事件,敲擊鍵盤,鼠標點擊 128 def get_event(self, my_tank, screem): 129 for event in pygame.event.get(): 130 if event.type == pygame.QUIT: # 我方坦克犧牲后不能按Esc恩退出 131 self.stopGame() 132 if event.type == pygame.KEYDOWN and (not TankMain.my_tank) and ( 133 event.key == pygame.K_r or event.key == pygame.K_n): # 按n或r復活 134 TankMain.my_tank = My_TanK(screem) # 我方坦克不復活不可以按Esc退出 135 TankMain.live_count -= 1 136 if TankMain.live_count == 0: 137 sys.exit() 138 if event.type == pygame.KEYDOWN and my_tank: 139 if event.key == pygame.K_LEFT or event.key == pygame.K_a: 140 my_tank.direction = "L" 141 my_tank.stop = False 142 if event.key == pygame.K_RIGHT or event.key == pygame.K_d: 143 my_tank.direction = "R" 144 my_tank.stop = False 145 if event.key == pygame.K_UP or event.key == pygame.K_w: 146 my_tank.direction = 'U' 147 my_tank.stop = False 148 if event.key == pygame.K_DOWN or event.key == pygame.K_x: 149 my_tank.direction = "D" 150 my_tank.stop = False 151 if event.key == pygame.K_ESCAPE: 152 self.stopGame() 153 if event.key == pygame.K_SPACE: 154 m = my_tank.fire() 155 m.good = True 156 TankMain.my_tank_missile.append(m) 157 if event.type == pygame.K_UP: 158 if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN or event.key == pygame.K_a or event.key == pygame.K_d or event.key == pygame.K_w or event.key == pygame.K_x: 159 my_tank.stop = True 160 if event.type == pygame.MOUSEMOTION: 161 pass 162 163 164 # 坦克大戰中所有對象的父類 165 class BaseItem(pygame.sprite.Sprite): 166 def __init__(self, screem): 167 pygame.sprite.Sprite.__init__(self) 168 self.screem = screem 169 170 def display(self): 171 if self.live: 172 self.image = self.images[self.direction] 173 self.screem.blit(self.image, self.rect) 174 175 176 # 坦克類 177 class Tank(BaseItem): 178 Width = 48 179 Height = 48 180 181 def __init__(self, screem, left, top): 182 super().__init__(screem) 183 self.screem = screem 184 self.direction = "D" # 坦克默認方向向下(上下左右) 185 self.speed = 5 # 坦克移動速度 186 self.stop = False 187 self.images = {} # 坦克圖集 188 self.images['L'] = pygame.image.load('image/enemytank/tankl.png') 189 self.images['R'] = pygame.image.load('image/enemytank/tankr.png') 190 self.images['U'] = pygame.image.load('image/enemytank/tanku.png') 191 self.images['D'] = pygame.image.load('image/enemytank/tankd.png') 192 self.image = self.images[self.direction] 193 self.rect = self.image.get_rect() 194 self.rect.left = left 195 self.rect.top = top 196 self.live = True # 覺得坦克是否存活 197 self.oldtop = self.rect.top 198 self.oldleft = self.rect.left 199 # 將坦克對相應圖片顯示在游戲窗口 200 def stay(self): 201 self.rect.left = self.oldleft 202 self.rect.top = self.oldtop 203 def move(self): 204 if not self.stop: 205 self.oldtop = self.rect.left 206 self.oldleft = self.rect.top 207 if self.direction == "L": 208 if self.rect.left > 0: # 坦克是否到達左邊界 209 self.rect.left -= self.speed 210 else: 211 self.rect.left = 0 212 elif self.direction == "R": 213 if self.rect.right < TankMain.Width: 214 self.rect.right += self.speed 215 else: 216 self.rect.right = TankMain.Width 217 elif self.direction == "U": 218 if self.rect.top > 0: 219 self.rect.top -= self.speed 220 else: 221 self.rect.top = 0 222 elif self.direction == "D": 223 if self.rect.top < TankMain.Height: 224 self.rect.top += self.speed 225 else: 226 self.rect.top = TankMain.Height 227 else: 228 pass 229 def fire(self): 230 m = Missile(self.screem, self) 231 return m 232 233 234 class My_TanK(Tank): 235 def __init__(self, screem): 236 super().__init__(screem, 275, 450) 237 self.images = {} # 坦克圖集 238 self.images['L'] = pygame.image.load('image/my_tank/mytankl.png') 239 self.images['R'] = pygame.image.load('image/my_tank/mytankr.png') 240 self.images['U'] = pygame.image.load('image/my_tank/mytanku.png') 241 self.images['D'] = pygame.image.load('image/my_tank/mytankd.png') 242 self.image = self.images[self.direction] 243 self.rect = self.image.get_rect() 244 245 def hit_enemy_missile(self): 246 hit_list = pygame.sprite.spritecollide(self, TankMain.enemy_missile_list, True) 247 for m in hit_list: # 我方坦克中彈 248 m.live = False 249 TankMain.enemy_missile_list.remove(m) 250 self.live = False 251 explode = Explode(self.screem, self.rect) 252 TankMain.explode_list.append(explode) 253 254 255 class Enemy_TanK(Tank): 256 def __init__(self, screem): 257 super().__init__(screem, randint(0, TankMain.Height), randint(0, TankMain.Width)) 258 self.step = randint(5, 10) 259 self.get_random_direction() 260 def get_random_direction(self): 261 r = randint(0, 4) 262 if r == 0: 263 self.stop = True 264 elif r == 1: 265 self.direction = 'L' 266 self.stop = False 267 elif r == 2: 268 self.direction = 'R' 269 self.stop = False 270 elif r == 3: 271 self.direction = 'U' 272 self.stop = False 273 elif r == 4: 274 self.direction = 'D' 275 self.stop = False 276 else: 277 pass 278 # 敵方坦克按隨機方向連續移動多步才改變方向 279 def random_move(self): 280 if self.live: 281 if self.step == 0: 282 self.get_random_direction() 283 self.step = randint(5, 10) 284 else: 285 self.move() 286 self.step -= 1 287 def random_fire(self): 288 r = randint(0, 50) 289 if r > 45: 290 m = self.fire() 291 TankMain.enemy_missile_list.add(m) 292 else: 293 return 294 295 296 class Missile(BaseItem): 297 Width = 8 298 Height = 8 299 def __init__(self, screem, tank): 300 # super().__init__(screem)坑 301 # print('error') 302 super().__init__(screem) 303 self.screem = screem 304 self.tank = tank 305 self.direction = tank.direction # 炮彈方向隨坦克默認方向向下(上下左右) 306 self.speed = 60 # 炮彈移動速度 307 self.stop = False 308 self.images = {} # 坦克圖集 309 self.images['L'] = pygame.image.load('image/missile/missile.png') 310 self.images['R'] = pygame.image.load('image/missile/missile.png') 311 self.images['U'] = pygame.image.load('image/missile/missile.png') 312 self.images['D'] = pygame.image.load('image/missile/missile.png') 313 self.image = self.images[self.direction] 314 self.rect = self.image.get_rect() 315 self.rect.left = tank.rect.left + (tank.Width - self.Width) / 2 316 self.rect.top = tank.rect.top + (tank.Height - self.Height) / 2 317 self.live = True # 決定炮彈是否存在 318 self.good = False 319 def move(self): 320 if self.live: 321 if self.direction == "L": 322 if self.rect.left > 0: # 坦克是否到達左邊界 323 self.rect.left -= self.speed 324 else: 325 self.live = False 326 elif self.direction == "R": 327 if self.rect.right < TankMain.Width: 328 self.rect.right += self.speed 329 else: 330 self.live = False 331 elif self.direction == "U": 332 if self.rect.top > 0: 333 self.rect.top -= self.speed 334 else: 335 self.live = False 336 elif self.direction == "D": 337 if self.rect.top < TankMain.Height: 338 self.rect.top += self.speed 339 else: 340 self.live = False 341 else: 342 pass 343 # 炮彈擊中坦克:我擊中敵法、敵方擊中我 344 def hit_tank(self): 345 if self.good: # 如果是我方炮彈 346 hit_list = pygame.sprite.spritecollide(self, TankMain.enemy_list, True) # 返回發生碰撞的列表 347 for e in hit_list: 348 e.live = False 349 TankMain.enemy_list.remove(e) 350 self.live = False 351 explode = Explode(self.screem, e.rect) 352 TankMain.explode_list.append(explode) 353 354 else: # 如果是敵方炮彈 355 pass 356 357 358 class Explode(BaseItem): 359 def __init__(self, screem, rect): 360 super().__init__(screem) 361 self.live = True 362 self.screem = screem 363 self.images = [pygame.image.load('image/explode/0.png'), \ 364 pygame.image.load('image/explode/1.png'), \ 365 pygame.image.load('image/explode/2.png'), \ 366 pygame.image.load('image/explode/3.png'), \ 367 pygame.image.load('image/explode/4.png'), \ 368 pygame.image.load('image/explode/5.png'), \ 369 ] 370 self.step = 0 371 self.rect = rect # 爆炸的位置和發送爆炸前坦克位置一樣,所以傳入坦克位置 372 373 # 循環調用 374 def display(self): 375 if self.live: 376 if self.step == len(self.images): # 最后一張爆炸圖片已經顯示 377 self.live = False 378 else: 379 self.image = self.images[self.step] 380 self.screem.blit(self.image, self.rect) 381 self.step += 1 382 383 else: 384 pass 385 386 ''' 387 牆: 388 能否被擊毀: 389 能否穿透 390 是否存活 391 草皮: 392 能穿過、不能擊毀、一直存活 393 磚牆: 394 不能闖過、能擊毀、被擊毀則不存活 395 鐵牆: 396 不能穿透、不能擊毀、一直存活 397 ''' 398 399 class SteelsWall(BaseItem): 400 def __init__(self, screem, left, top): 401 super().__init__(screem) 402 self.live = True # 存活指標 403 self.via = False # 穿透指標 404 self.quality = True # 能否被炮彈擊毀,但后來沒用到 405 self.image = pygame.image.load('image/barrier/steels.png') 406 self.rect = self.image.get_rect() 407 self.rect.left = left # randint(10,500) 408 self.rect.top = top # randint(10,400) 409 def display(self): 410 if self.live: 411 self.screem.blit(self.image, self.rect) 412 else: 413 pass 414 def hit_tank(self): 415 if TankMain.my_tank and (not self.via) and self.live: 416 hit_list1 = pygame.sprite.collide_circle(self, TankMain.my_tank) 417 if hit_list1: 418 TankMain.my_tank.stop = True 419 TankMain.my_tank.stay() # 我方坦克,調用該函數有點小毛病,穿越? 420 else: 421 pass 422 if TankMain.enemy_list and (not self.via) and self.live: 423 hit_list2 = pygame.sprite.spritecollide(self, TankMain.enemy_list, False) 424 for e in hit_list2: 425 e.stop = True 426 e.stay() # 略有問題但不明顯 427 def hit_missile(self): 428 missile_list = pygame.sprite.Group() 429 for i in TankMain.enemy_missile_list: 430 missile_list.add(i) 431 for j in (TankMain.my_tank_missile): 432 missile_list.add(j) 433 if missile_list and (not self.via) and self.live: 434 hit_list=pygame.sprite.spritecollide(self,missile_list,False) 435 for missile in hit_list: 436 missile.stop=True 437 missile.speed=0 438 439 class GrassWall(SteelsWall): 440 def __init__(self, screem, left, top): 441 super().__init__(screem, left, top) 442 self.image = pygame.image.load('image/barrier/grasss.png') 443 self.via = True 444 445 446 class BlockWall(SteelsWall): 447 def __init__(self, screem, left, top): 448 super().__init__(screem, left, top) 449 self.image = pygame.image.load('image/barrier/walls.png') 450 self.quality = False 451 self.live = True 452 self.via = False 453 def hit_missile(self): 454 missile_group=pygame.sprite.Group() 455 for i in TankMain.enemy_missile_list: 456 missile_group.add(i) 457 for j in TankMain.my_tank_missile: 458 missile_group.add(j) 459 if missile_group: 460 hit_list=pygame.sprite.spritecollide(self,missile_group,False) 461 if hit_list: 462 self.live=False 463 for i in hit_list: 464 i.speed=0 465 i.stop=True 466 i.live=False 467 ##提取碼:f9lv 468 469 470 if __name__ == '__main__': 471 game = TankMain() 472 game.startGame() 473 game.stopGame() 474